MFHead @347527

Sponsored by:	The FreeBSD Foundation
This commit is contained in:
Alan Somers 2019-05-13 18:25:55 +00:00
commit 7648bc9fee
2789 changed files with 147961 additions and 60788 deletions

19
.cirrus.yml Normal file
View File

@ -0,0 +1,19 @@
# $FreeBSD$
freebsd_instance:
image: freebsd-12-0-release-amd64
cpu: 8
memory: 24G
env:
CIRRUS_CLONE_DEPTH: 1
task:
timeout_in: 90m
install_script:
- pkg install -y qemu-devel
- fetch https://people.freebsd.org/~emaste/OVMF.fd
script:
- make -j$(sysctl -n hw.ncpu) WITHOUT_TOOLCHAIN=yes buildworld buildkernel
test_script:
- OVMF=$(pwd)/OVMF.fd sh tools/boot/ci-qemu-test.sh

View File

@ -35,17 +35,19 @@ makes a commit to the specified subtree.
subsystem login notes
-----------------------------
atf freebsd-testing,jmmv,ngie Pre-commit review requested.
ath(4) adrian Pre-commit review requested, send to freebsd-wireless@freebsd.org
contrib/atf ngie,#test Pre-commit review requested.
contrib/capsicum-test ngie,#capsicum,#test Pre-commit review requested.
contrib/compiler-rt dim Pre-commit review preferred.
contrib/googletest ngie,#test Pre-commit review requested.
contrib/ipfilter cy Pre-commit review requested.
contrib/libc++ dim Pre-commit review preferred.
contrib/libcxxrt dim Pre-commit review preferred.
contrib/libunwind dim,emaste,jhb Pre-commit review preferred.
contrib/llvm dim Pre-commit review preferred.
contrib/llvm/tools/lldb dim,emaste Pre-commit review preferred.
contrib/netbsd-tests freebsd-testing,ngie Pre-commit review requested.
contrib/pjdfstest freebsd-testing,asomers,ngie,pjd Pre-commit review requested.
contrib/netbsd-tests ngie,#test Pre-commit review requested.
contrib/pjdfstest asomers,ngie,pjd,#test Pre-commit review requested.
*env(3) secteam Due to the problematic security history of this
code, please have patches reviewed by secteam.
etc/mail gshapiro Pre-commit review requested. Keep in sync with -STABLE.
@ -86,10 +88,15 @@ sh(1) jilles Pre-commit review requested. This also applies
to kill(1), printf(1) and test(1) which are
compiled in as builtins.
share/mk imp, bapt, bdrewery, emaste, sjg Make is hard.
share/mk/*.test.mk freebsd-testing,ngie (same list as share/mk too) Pre-commit review requested.
share/mk/*.test.mk imp,bapt,bdrewery, Pre-commit review requested.
emaste,ngie,sjg,#test
stand/forth dteske Pre-commit review requested.
stand/lua kevans Pre-commit review requested
sys/compat/linuxkpi hselasky If in doubt, ask.
sys/compat/linuxkpi hselasky If in doubt, ask.
zeising, johalun pre-commit review requested via
#x11 phabricator group.
(to avoid drm graphics drivers
impact)
sys/contrib/ipfilter cy Pre-commit review requested.
sys/dev/e1000 erj Pre-commit phabricator review requested.
sys/dev/ixgbe erj Pre-commit phabricator review requested.
@ -101,7 +108,8 @@ sys/netinet/ip_carp.c glebius Pre-commit review recommended.
sys/netpfil/pf kp,glebius Pre-commit review recommended.
sys/x86/xen royger Pre-commit review recommended.
sys/xen royger Pre-commit review recommended.
tests freebsd-testing,ngie Pre-commit review requested.
tests ngie,#test Pre-commit review requested.
tools/build imp Pre-commit review requested, especially to fix bootstrap issues.
top(1) eadler Pre-commit review requested.
usr.sbin/bsdconfig dteske Pre-commit phabricator review requested.
usr.sbin/dpv dteske Pre-commit review requested. Keep in sync with libdpv.

View File

@ -570,7 +570,7 @@ universe-toolchain: .PHONY universe_prologue
false; \
fi
@if [ ! -e "${HOST_OBJTOP}/tmp/usr/bin/ld" ]; then \
echo "Missing host linker at ${HOST_OBJTOP}/tmp/usr/bin/cc?" >&2; \
echo "Missing host linker at ${HOST_OBJTOP}/tmp/usr/bin/ld?" >&2; \
false; \
fi
@echo "--------------------------------------------------------------"

View File

@ -2570,6 +2570,7 @@ NXBDIRS+= \
usr.bin/true \
usr.bin/uniq \
usr.bin/unzip \
usr.bin/wc \
usr.bin/xargs \
usr.bin/xinstall \
usr.bin/xz \
@ -2601,6 +2602,7 @@ NXBMAKEARGS+= \
-DNO_CPU_CFLAGS \
-DNO_PIC \
SSP_CFLAGS= \
MK_CASPER=no \
MK_CLANG_EXTRAS=no \
MK_CLANG_FULL=no \
MK_CTF=no \

View File

@ -38,6 +38,9 @@
# xargs -n1 | sort | uniq -d;
# done
# 20190509: tests/sys/opencrypto requires the net/py-dpkt package.
OLD_FILES+=usr/tests/sys/opencrypto/dpkt.py
OLD_FILES+=usr/tests/sys/opencrypto/dpkt.pyc
# 20190304: new libc++ import which bumps version from 7.0.1 to 8.0.0.
OLD_FILES+=usr/include/c++/v1/experimental/dynarray
# 20190304: new clang import which bumps version from 7.0.1 to 8.0.0.

View File

@ -31,11 +31,68 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 13.x IS SLOW:
disable the most expensive debugging functionality run
"ln -s 'abort:false,junk:false' /etc/malloc.conf".)
20190507:
The IPSEC option has been removed from GENERIC. Users requiring
ipsec(4) must now load the ipsec(4) kernel module.
20190507:
The tap(4) driver has been folded into tun(4), and the module has been
renamed to tuntap. You should update any kld_load="if_tap" or
kld_load="if_tun" entries in /etc/rc.conf, if_tap_load="YES" or
if_tun_load="YES" entries in /boot/loader.conf to load the if_tuntap
module instead, and "device tap" or "device tun" entries in kernel
config files to select the tuntap device instead.
20190418:
The following knobs have been added related to tradeoffs between
safe use of the random device and availability in the absence of
entropy:
kern.random.initial_seeding.bypass_before_seeding: tunable; set
non-zero to bypass the random device prior to seeding, or zero to
block random requests until the random device is initially seeded.
For now, set to 1 (unsafe) by default to restore pre-r346250 boot
availability properties.
kern.random.initial_seeding.read_random_bypassed_before_seeding:
read-only diagnostic sysctl that is set when bypass is enabled and
read_random(9) is bypassed, to enable programmatic handling of this
initial condition, if desired.
kern.random.initial_seeding.arc4random_bypassed_before_seeding:
Similar to the above, but for for arc4random(9) initial seeding.
kern.random.initial_seeding.disable_bypass_warnings: tunable; set
non-zero to disable warnings in dmesg when the same conditions are
met as for the diagnostic sysctls above. Defaults to zero, i.e.,
produce warnings in dmesg when the conditions are met.
20190416:
The tunable "security.stack_protect.permit_nonrandom_cookies" may be
set to a non-zero value to boot systems that do not provide early
entropy. Otherwise, such systems may see the panic message:
"cannot initialize stack cookies because random device is not yet
seeded."
20190416:
The loadable random module KPI has changed; the random_infra_init()
routine now requires a 3rd function pointer for a bool (*)(void)
method that returns true if the random device is seeded (and
therefore unblocked).
20190404:
r345895 reverts r320698. This implies that an nfsuserd(8) daemon
built from head sources between r320757 (July 6, 2017) and
r338192 (Aug. 22, 2018) will not work unless the "-use-udpsock"
is added to the command line.
nfsuserd daemons built from head sources that are post-r338192 are
not affected and should continue to work.
20190320:
The fuse(4) module has been renamed to fusefs(4) for consistency with
other filesystems. You should update any kld_load="fuse" entries in
/etc/rc.conf, fuse_load="YES" entries in /boot/loader.conf, and
"options FUSE" enties in kernel config files.
"options FUSE" entries in kernel config files.
20190304:
Clang, llvm, lld, lldb, compiler-rt and libc++ have been upgraded to
@ -99,7 +156,7 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 13.x IS SLOW:
20181211:
Remove the timed and netdate programs from the base tree. Setting
the time with these deamons has been obsolete for over a decade.
the time with these daemons has been obsolete for over a decade.
20181126:
On amd64, arm64 and armv7 (architectures that install LLVM's ld.lld
@ -162,7 +219,7 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 13.x IS SLOW:
20181009:
OpenSSL has been updated to version 1.1.1. This update included
additional various API changes througout the base system. It is
additional various API changes throughout the base system. It is
important to rebuild third-party software after upgrading. The value
of __FreeBSD_version has been bumped accordingly.
@ -259,13 +316,13 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 13.x IS SLOW:
20180719:
ARM64 now have efifb support, if you want to have serial console
on your arm64 board when an screen is connected and the bootloader
setup a framebuffer for us to use, just add :
setup a frame buffer for us to use, just add :
boot_serial=YES
boot_multicons=YES
in /boot/loader.conf
For Raspberry Pi 3 (RPI) users, this is needed even if you don't have
an screen connected as the firmware will setup a framebuffer are that
u-boot will expose as an EFI framebuffer.
an screen connected as the firmware will setup a frame buffer are that
u-boot will expose as an EFI frame buffer.
20180719:
New uid:gid added, ntpd:ntpd (123:123). Be sure to run mergemaster
@ -364,7 +421,7 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 13.x IS SLOW:
20180508:
The nxge(4) driver has been removed. This driver was for PCI-X 10g
cards made by s2io/Neterion. The company was aquired by Exar and
cards made by s2io/Neterion. The company was acquired by Exar and
no longer sells or supports Ethernet products. If you have device
nxge in your kernel config file it must be removed.
@ -455,7 +512,7 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 13.x IS SLOW:
20180212:
FreeBSD boot loader enhanced with Lua scripting. It's purely opt-in for
now by building WITH_LOADER_LUA and WITHOUT_FORTH in /etc/src.conf.
Co-existance for the transition period will come shortly. Booting is a
Co-existence for the transition period will come shortly. Booting is a
complex environment and test coverage for Lua-enabled loaders has been
thin, so it would be prudent to assume it might not work and make
provisions for backup boot methods.

View File

@ -32,7 +32,7 @@
.\" @(#)date.1 8.3 (Berkeley) 4/28/95
.\" $FreeBSD$
.\"
.Dd March 20, 2019
.Dd April 23, 2019
.Dt DATE 1
.Os
.Sh NAME
@ -40,7 +40,7 @@
.Nd display or set date and time
.Sh SYNOPSIS
.Nm
.Op Fl jRu
.Op Fl jnRu
.Op Fl r Ar seconds | Ar filename
.Oo
.Fl v
@ -142,6 +142,8 @@ This allows you to use the
flag in addition to the
.Cm +
option to convert one date format to another.
.It Fl n
Obsolete flag, accepted and ignored for compatibility.
.It Fl R
Use RFC 2822 date and time output format.
This is equivalent to using

View File

@ -108,7 +108,7 @@ main(int argc, char *argv[])
(void) setlocale(LC_TIME, "");
rflag = 0;
Iflag = jflag = Rflag = 0;
while ((ch = getopt(argc, argv, "f:I::jRr:uv:")) != -1)
while ((ch = getopt(argc, argv, "f:I::jnRr:uv:")) != -1)
switch((char)ch) {
case 'f':
fmt = optarg;
@ -132,6 +132,8 @@ main(int argc, char *argv[])
case 'j':
jflag = 1; /* don't set time */
break;
case 'n':
break;
case 'R': /* RFC 2822 datetime format */
if (Iflag)
multipleformats();

View File

@ -58,8 +58,26 @@ DIR=/var/tmp/dtest.$$
sctpport=1024
bound=5000
mkdir $DIR
cd $DIR
cat > client.pl <<-EOPERL
use IO::Socket;
my \$s = IO::Socket::INET->new(
Type => SOCK_STREAM,
Proto => "sctp",
LocalAddr => "$local",
PeerAddr => "$local",
PeerPort => \$ARGV[0],
Timeout => 3);
die "Could not connect to host $local port \$ARGV[0] \$@" unless \$s;
close \$s;
sleep(\$ARGV[1]);
EOPERL
while [ $sctpport -lt $bound ]; do
ncat --sctp -z $local $sctpport > /dev/null || break
perl client.pl $sctpport 0 2>&- || break
sctpport=$(($sctpport + 1))
done
if [ $sctpport -eq $bound ]; then
@ -67,27 +85,25 @@ if [ $sctpport -eq $bound ]; then
exit 1
fi
mkdir $DIR
cd $DIR
# ncat will exit when the association is closed.
ncat --sctp --listen $local $sctpport &
cat > test.pl <<-EOPERL
cat > server.pl <<-EOPERL
use IO::Socket;
my \$s = IO::Socket::INET->new(
my \$l = IO::Socket::INET->new(
Type => SOCK_STREAM,
Proto => "sctp",
LocalAddr => "$local",
PeerAddr => "$local",
PeerPort => $sctpport,
Timeout => 3);
die "Could not connect to host $local port $sctpport \$@" unless \$s;
close \$s;
sleep(2);
LocalPort => $sctpport,
Listen => 1,
Reuse => 1);
die "Could not listen on $local port $sctpport \$@" unless \$l;
my \$c = \$l->accept();
close \$l;
while (<\$c>) {};
close \$c;
EOPERL
$dtrace -c 'perl test.pl' -qs /dev/stdin <<EODTRACE
perl server.pl &
$dtrace -c "perl client.pl $sctpport 2" -qs /dev/stdin <<EODTRACE
BEGIN
{
ipsend = sctpsend = ipreceive = sctpreceive = 0;
@ -122,10 +138,10 @@ sctp:::receive
END
{
printf("Minimum SCTP events seen\n\n");
printf("ip:::send (%d) - %s\n", ipsend, ipsend >= 7 ? "yes" : "no");
printf("ip:::receive (%d) - %s\n", ipreceive, ipreceive >= 7 ? "yes" : "no");
printf("sctp:::send (%d) - %s\n", sctpsend, sctpsend >= 7 ? "yes" : "no");
printf("sctp:::receive (%d) - %s\n", sctpreceive, sctpreceive >= 7 ? "yes" : "no");
printf("ip:::send - %s\n", ipsend >= 7 ? "yes" : "no");
printf("ip:::receive - %s\n", ipreceive >= 7 ? "yes" : "no");
printf("sctp:::send - %s\n", sctpsend >= 7 ? "yes" : "no");
printf("sctp:::receive - %s\n", sctpreceive >= 7 ? "yes" : "no");
}
EODTRACE

View File

@ -61,8 +61,26 @@ DIR=/var/tmp/dtest.$$
sctpport=1024
bound=5000
mkdir $DIR
cd $DIR
cat > client.pl <<-EOPERL
use IO::Socket;
my \$s = IO::Socket::INET->new(
Type => SOCK_STREAM,
Proto => "sctp",
LocalAddr => "$local",
PeerAddr => "$local",
PeerPort => \$ARGV[0],
Timeout => 3);
die "Could not connect to host $local port \$ARGV[0] \$@" unless \$s;
close \$s;
sleep(\$ARGV[1]);
EOPERL
while [ $sctpport -lt $bound ]; do
ncat --sctp -z $local $sctpport > /dev/null || break
perl client.pl $sctpport 0 2>&- || break
sctpport=$(($sctpport + 1))
done
if [ $sctpport -eq $bound ]; then
@ -70,27 +88,25 @@ if [ $sctpport -eq $bound ]; then
exit 1
fi
mkdir $DIR
cd $DIR
# ncat will exit when the association is closed.
ncat --sctp --listen $local $sctpport &
cat > test.pl <<-EOPERL
cat > server.pl <<-EOPERL
use IO::Socket;
my \$s = IO::Socket::INET->new(
my \$l = IO::Socket::INET->new(
Type => SOCK_STREAM,
Proto => "sctp",
LocalAddr => "$local",
PeerAddr => "$local",
PeerPort => $sctpport,
Timeout => 3);
die "Could not connect to host $local port $sctpport \$@" unless \$s;
close \$s;
sleep(2);
LocalPort => $sctpport,
Listen => 1,
Reuse => 1);
die "Could not listen on $local port $sctpport \$@" unless \$l;
my \$c = \$l->accept();
close \$l;
while (<\$c>) {};
close \$c;
EOPERL
$dtrace -c 'perl test.pl' -qs /dev/stdin <<EODTRACE
perl server.pl &
$dtrace -c "perl client.pl $sctpport 2" -qs /dev/stdin <<EODTRACE
BEGIN
{
ipsend = sctpsend = ipreceive = sctpreceive = 0;

View File

@ -10,3 +10,4 @@ sctp:::state-change to established - yes
sctp:::state-change to shutdown-sent - yes
sctp:::state-change to shutdown-received - yes
sctp:::state-change to shutdown-ack-sent - yes

View File

@ -225,7 +225,7 @@ zfs_compare(const void *larg, const void *rarg, void *unused)
*rat = '\0';
ret = strcmp(lname, rname);
if (ret == 0) {
if (ret == 0 && (lat != NULL || rat != NULL)) {
/*
* If we're comparing a dataset to one of its snapshots, we
* always make the full dataset first.

View File

@ -30,7 +30,7 @@ INCFLAGS+= -I${SRCTOP}/sys/cddl/contrib/opensolaris/uts/common
INCFLAGS+= -I${SRCTOP}/sys/cddl/contrib/opensolaris/uts/common/fs/zfs
INCFLAGS+= -I${SRCTOP}/cddl/usr.sbin
CFLAGS= -g -DNEED_SOLARIS_BOOLEAN ${INCFLAGS}
CFLAGS+= -DNEED_SOLARIS_BOOLEAN ${INCFLAGS}
LIBADD+= devdctl zfs zfs_core util geom bsdxml sbuf nvpair uutil

View File

@ -225,6 +225,15 @@ struct flag_desc {
const char *desc;
};
struct loc_at {
Dwarf_Attribute la_at;
Dwarf_Unsigned la_off;
Dwarf_Unsigned la_lowpc;
Dwarf_Half la_cu_psize;
Dwarf_Half la_cu_osize;
Dwarf_Half la_cu_ver;
};
static void add_dumpop(struct readelf *re, size_t si, const char *sn, int op,
int t);
static const char *aeabi_adv_simd_arch(uint64_t simd);
@ -341,6 +350,7 @@ static const char *get_string(struct readelf *re, int strtab, size_t off);
static const char *get_symbol_name(struct readelf *re, int symtab, int i);
static uint64_t get_symbol_value(struct readelf *re, int symtab, int i);
static void load_sections(struct readelf *re);
static int loc_at_comparator(const void *la1, const void *la2);
static const char *mips_abi_fp(uint64_t fp);
static const char *note_type(const char *note_name, unsigned int et,
unsigned int nt);
@ -359,7 +369,8 @@ static const char *ppc_abi_vector(uint64_t vec);
static void readelf_usage(int status);
static void readelf_version(void);
static void search_loclist_at(struct readelf *re, Dwarf_Die die,
Dwarf_Unsigned lowpc);
Dwarf_Unsigned lowpc, struct loc_at **la_list,
size_t *la_list_len, size_t *la_list_cap);
static void search_ver(struct readelf *re);
static const char *section_type(unsigned int mach, unsigned int stype);
static void set_cu_context(struct readelf *re, Dwarf_Half psize,
@ -6034,21 +6045,27 @@ dump_dwarf_str(struct readelf *re)
}
}
struct loc_at {
Dwarf_Attribute la_at;
Dwarf_Unsigned la_off;
Dwarf_Unsigned la_lowpc;
Dwarf_Half la_cu_psize;
Dwarf_Half la_cu_osize;
Dwarf_Half la_cu_ver;
TAILQ_ENTRY(loc_at) la_next;
};
static int
loc_at_comparator(const void *la1, const void *la2)
{
const struct loc_at *left, *right;
static TAILQ_HEAD(, loc_at) lalist = TAILQ_HEAD_INITIALIZER(lalist);
left = (const struct loc_at *)la1;
right = (const struct loc_at *)la2;
if (left->la_off > right->la_off)
return (1);
else if (left->la_off < right->la_off)
return (-1);
else
return (0);
}
static void
search_loclist_at(struct readelf *re, Dwarf_Die die, Dwarf_Unsigned lowpc)
search_loclist_at(struct readelf *re, Dwarf_Die die, Dwarf_Unsigned lowpc,
struct loc_at **la_list, size_t *la_list_len, size_t *la_list_cap)
{
struct loc_at *la;
Dwarf_Attribute *attr_list;
Dwarf_Die ret_die;
Dwarf_Unsigned off;
@ -6057,7 +6074,6 @@ search_loclist_at(struct readelf *re, Dwarf_Die die, Dwarf_Unsigned lowpc)
Dwarf_Half attr, form;
Dwarf_Bool is_info;
Dwarf_Error de;
struct loc_at *la, *nla;
int i, ret;
is_info = dwarf_get_die_infotypes_flag(die);
@ -6105,33 +6121,21 @@ search_loclist_at(struct readelf *re, Dwarf_Die die, Dwarf_Unsigned lowpc)
} else
continue;
TAILQ_FOREACH(la, &lalist, la_next) {
if (off == la->la_off)
break;
if (off < la->la_off) {
if ((nla = malloc(sizeof(*nla))) == NULL)
err(EXIT_FAILURE, "malloc failed");
nla->la_at = attr_list[i];
nla->la_off = off;
nla->la_lowpc = lowpc;
nla->la_cu_psize = re->cu_psize;
nla->la_cu_osize = re->cu_osize;
nla->la_cu_ver = re->cu_ver;
TAILQ_INSERT_BEFORE(la, nla, la_next);
break;
}
}
if (la == NULL) {
if ((nla = malloc(sizeof(*nla))) == NULL)
err(EXIT_FAILURE, "malloc failed");
nla->la_at = attr_list[i];
nla->la_off = off;
nla->la_lowpc = lowpc;
nla->la_cu_psize = re->cu_psize;
nla->la_cu_osize = re->cu_osize;
nla->la_cu_ver = re->cu_ver;
TAILQ_INSERT_TAIL(&lalist, nla, la_next);
if (*la_list_cap == *la_list_len) {
*la_list = realloc(*la_list,
*la_list_cap * 2 * sizeof(**la_list));
if (la_list == NULL)
errx(EXIT_FAILURE, "realloc failed");
*la_list_cap *= 2;
}
la = &((*la_list)[*la_list_len]);
la->la_at = attr_list[i];
la->la_off = off;
la->la_lowpc = lowpc;
la->la_cu_psize = re->cu_psize;
la->la_cu_osize = re->cu_osize;
la->la_cu_ver = re->cu_ver;
(*la_list_len)++;
}
cont_search:
@ -6140,14 +6144,16 @@ search_loclist_at(struct readelf *re, Dwarf_Die die, Dwarf_Unsigned lowpc)
if (ret == DW_DLV_ERROR)
warnx("dwarf_child: %s", dwarf_errmsg(de));
else if (ret == DW_DLV_OK)
search_loclist_at(re, ret_die, lowpc);
search_loclist_at(re, ret_die, lowpc, la_list,
la_list_len, la_list_cap);
/* Search sibling. */
ret = dwarf_siblingof_b(re->dbg, die, &ret_die, is_info, &de);
if (ret == DW_DLV_ERROR)
warnx("dwarf_siblingof: %s", dwarf_errmsg(de));
else if (ret == DW_DLV_OK)
search_loclist_at(re, ret_die, lowpc);
search_loclist_at(re, ret_die, lowpc, la_list,
la_list_len, la_list_cap);
}
static void
@ -6430,9 +6436,15 @@ dump_dwarf_loclist(struct readelf *re)
Dwarf_Signed lcnt;
Dwarf_Half tag, version, pointer_size, off_size;
Dwarf_Error de;
struct loc_at *la;
struct loc_at *la_list, *left, *right, *la;
size_t la_list_len, la_list_cap;
unsigned int duplicates, k;
int i, j, ret, has_content;
la_list_len = 0;
la_list_cap = 200;
if ((la_list = calloc(la_list_cap, sizeof(struct loc_at))) == NULL)
errx(EXIT_FAILURE, "calloc failed");
/* Search .debug_info section. */
while ((ret = dwarf_next_cu_header_b(re->dbg, NULL, &version, NULL,
&pointer_size, &off_size, NULL, NULL, &de)) == DW_DLV_OK) {
@ -6453,7 +6465,8 @@ dump_dwarf_loclist(struct readelf *re)
}
/* Search attributes for reference to .debug_loc section. */
search_loclist_at(re, die, lowpc);
search_loclist_at(re, die, lowpc, &la_list,
&la_list_len, &la_list_cap);
}
if (ret == DW_DLV_ERROR)
warnx("dwarf_next_cu_header: %s", dwarf_errmsg(de));
@ -6485,17 +6498,37 @@ dump_dwarf_loclist(struct readelf *re)
* Search attributes for reference to .debug_loc
* section.
*/
search_loclist_at(re, die, lowpc);
search_loclist_at(re, die, lowpc, &la_list,
&la_list_len, &la_list_cap);
}
if (ret == DW_DLV_ERROR)
warnx("dwarf_next_cu_header: %s", dwarf_errmsg(de));
} while (dwarf_next_types_section(re->dbg, &de) == DW_DLV_OK);
if (TAILQ_EMPTY(&lalist))
if (la_list_len == 0) {
free(la_list);
return;
}
/* Sort la_list using loc_at_comparator. */
qsort(la_list, la_list_len, sizeof(struct loc_at), loc_at_comparator);
/* Get rid of the duplicates in la_list. */
duplicates = 0;
for (k = 1; k < la_list_len; ++k) {
left = &la_list[k - 1 - duplicates];
right = &la_list[k];
if (left->la_off == right->la_off)
duplicates++;
else
la_list[k - duplicates] = *right;
}
la_list_len -= duplicates;
has_content = 0;
TAILQ_FOREACH(la, &lalist, la_next) {
for (k = 0; k < la_list_len; ++k) {
la = &la_list[k];
if ((ret = dwarf_loclist_n(la->la_at, &llbuf, &lcnt, &de)) !=
DW_DLV_OK) {
if (ret != DW_DLV_NO_ENTRY)
@ -6545,6 +6578,8 @@ dump_dwarf_loclist(struct readelf *re)
if (!has_content)
printf("\nSection '.debug_loc' has no debugging data.\n");
free(la_list);
}
/*
@ -6892,7 +6927,6 @@ dump_elf(struct readelf *re)
static void
dump_dwarf(struct readelf *re)
{
struct loc_at *la, *_la;
Dwarf_Error de;
int error;
@ -6930,11 +6964,6 @@ dump_dwarf(struct readelf *re)
if (re->dop & DW_O)
dump_dwarf_loclist(re);
TAILQ_FOREACH_SAFE(la, &lalist, la_next, _la) {
TAILQ_REMOVE(&lalist, la, la_next);
free(la);
}
dwarf_finish(re->dbg, &de);
}

View File

@ -195,7 +195,7 @@ main(int argc, char **argv)
argv += optind;
cap_rights_init(&rights, CAP_READ, CAP_SEEK, CAP_FSTAT, CAP_FCNTL);
fa = fileargs_init(argc, argv, O_RDONLY, 0, &rights);
fa = fileargs_init(argc, argv, O_RDONLY, 0, &rights, FA_OPEN);
if (fa == NULL)
err(1, "Unable to initialize casper fileargs");

View File

@ -12,7 +12,7 @@
#
AC_PREREQ(2.2)
AC_INIT([libxo], [1.0.2], [phil@juniper.net])
AC_INIT([libxo], [1.0.4], [phil@juniper.net])
AM_INIT_AUTOMAKE([-Wall -Werror foreign -Wno-portability])
# Support silent build rules. Requires at least automake-1.11.

View File

@ -22011,7 +22011,7 @@ jQuery(function ($) {
</tr>
<tr>
<td class="header left"></td>
<td class="header right">April 2, 2019</td>
<td class="header right">April 24, 2019</td>
</tr>
</table></div>
<p id="title" class="title">libxo: The Easy Way to Generate text, XML, JSON, and HTML output<br><span class="filename">libxo-manual</span></p>

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014-2018, Juniper Networks, Inc.
* Copyright (c) 2014-2019, Juniper Networks, Inc.
* All rights reserved.
* This SOFTWARE is licensed under the LICENSE provided in the
* ../Copyright file. By downloading, installing, copying, or otherwise
@ -600,7 +600,7 @@ xo_no_setlocale (void)
static const char *
xo_xml_leader_len (xo_handle_t *xop, const char *name, xo_ssize_t nlen)
{
if (isalpha(name[0]) || name[0] == '_')
if (name == NULL || isalpha(name[0]) || name[0] == '_')
return "";
xo_failure(xop, "invalid XML tag name: '%.*s'", nlen, name);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, Juniper Networks, Inc.
* Copyright (c) 2019, Juniper Networks, Inc.
* All rights reserved.
* This SOFTWARE is licensed under the LICENSE provided in the
* ../Copyright file. By downloading, installing, copying, or otherwise

View File

@ -0,0 +1 @@
test_02: key field emitted after normal value field: 'name'

View File

@ -1,6 +1,10 @@
op create: [] [] [0]
op open_container: [top] [] [0x40010]
op open_container: [data] [] [0x40010]
op string: [name] [em0] [0x1080]
op string: [flags] [0x8843] [0x18]
op string: [name] [em0] [0x1088]
op string: [flags] [0x8843] [0x18]
op string: [what] [braces] [0]
op string: [length] [abcdef] [0]
op content: [fd] [-1] [0]

View File

@ -0,0 +1 @@
test_02: key field emitted after normal value field: 'name'

View File

@ -1,4 +1,4 @@
<div class="line"><div class="text">We are </div><div class="text">{emit}</div><div class="text">{ting}</div><div class="text"> some </div><div class="data" data-tag="what">braces</div></div><div class="line"><div class="message">abcdef
<div class="line"><div class="data" data-tag="name">em0 </div><div class="data">em0 </div><div class="text">We are </div><div class="text">{emit}</div><div class="text">{ting}</div><div class="text"> some </div><div class="data" data-tag="what">braces</div></div><div class="line"><div class="message">abcdef
</div></div><div class="line"><div class="message">abcdef: Bad file descriptor
</div></div><div class="line"><div class="message">improper use of profanity; ten yard penalty; first down
</div></div><div class="line"><div class="text">length </div><div class="data" data-tag="length">abcdef</div></div><div class="line"><div class="text">close </div><div class="data" data-tag="fd">-1</div><div class="text"> returned </div><div class="data" data-tag="error">Bad file descriptor</div><div class="text"> </div><div class="data" data-tag="test">good</div></div><div class="line"><div class="text">close </div><div class="data" data-tag="fd">-1</div><div class="text"> returned </div><div class="data" data-tag="error">Bad fi</div><div class="text"> </div><div class="data" data-tag="test">good</div></div><div class="line"><div class="message">improper use of profanity; ten yard penalty; first down

View File

@ -0,0 +1 @@
test_02: key field emitted after normal value field: 'name'

View File

@ -1,9 +1,11 @@
<div class="line">
<div class="data" data-tag="name" data-xpath="/top/data/name">em0 </div>
<div class="data">em0 </div>
<div class="text">We are </div>
<div class="text">{emit}</div>
<div class="text">{ting}</div>
<div class="text"> some </div>
<div class="data" data-tag="what" data-xpath="/top/data/what">braces</div>
<div class="data" data-tag="what" data-xpath="/top/data[name = 'em0 '][name = 'em0']/what">braces</div>
</div>
<div class="line">
<div class="message">abcdef
@ -19,23 +21,23 @@
</div>
<div class="line">
<div class="text">length </div>
<div class="data" data-tag="length" data-xpath="/top/data/length">abcdef</div>
<div class="data" data-tag="length" data-xpath="/top/data[name = 'em0 '][name = 'em0']/length">abcdef</div>
</div>
<div class="line">
<div class="text">close </div>
<div class="data" data-tag="fd" data-xpath="/top/data/fd">-1</div>
<div class="data" data-tag="fd" data-xpath="/top/data[name = 'em0 '][name = 'em0']/fd">-1</div>
<div class="text"> returned </div>
<div class="data" data-tag="error" data-xpath="/top/data/error">Bad file descriptor</div>
<div class="data" data-tag="error" data-xpath="/top/data[name = 'em0 '][name = 'em0']/error">Bad file descriptor</div>
<div class="text"> </div>
<div class="data" data-tag="test" data-xpath="/top/data/test">good</div>
<div class="data" data-tag="test" data-xpath="/top/data[name = 'em0 '][name = 'em0']/test">good</div>
</div>
<div class="line">
<div class="text">close </div>
<div class="data" data-tag="fd" data-xpath="/top/data/fd">-1</div>
<div class="data" data-tag="fd" data-xpath="/top/data[name = 'em0 '][name = 'em0']/fd">-1</div>
<div class="text"> returned </div>
<div class="data" data-tag="error" data-xpath="/top/data/error">Bad fi</div>
<div class="data" data-tag="error" data-xpath="/top/data[name = 'em0 '][name = 'em0']/error">Bad fi</div>
<div class="text"> </div>
<div class="data" data-tag="test" data-xpath="/top/data/test">good</div>
<div class="data" data-tag="test" data-xpath="/top/data[name = 'em0 '][name = 'em0']/test">good</div>
</div>
<div class="line">
<div class="message">improper use of profanity; ten yard penalty; first down
@ -43,155 +45,155 @@
</div>
<div class="line">
<div class="text"> </div>
<div class="data" data-tag="lines" data-xpath="/top/data/lines"> 20</div>
<div class="data" data-tag="lines" data-xpath="/top/data[name = 'em0 '][name = 'em0']/lines"> 20</div>
<div class="text"> </div>
<div class="data" data-tag="words" data-xpath="/top/data/words"> 30</div>
<div class="data" data-tag="words" data-xpath="/top/data[name = 'em0 '][name = 'em0']/words"> 30</div>
<div class="text"> </div>
<div class="data" data-tag="characters" data-xpath="/top/data/characters"> 40</div>
<div class="data" data-tag="characters" data-xpath="/top/data[name = 'em0 '][name = 'em0']/characters"> 40</div>
<div class="text"> </div>
<div class="data" data-tag="filename" data-xpath="/top/data/filename">file</div>
<div class="data" data-tag="filename" data-xpath="/top/data[name = 'em0 '][name = 'em0']/filename">file</div>
</div>
<div class="line">
<div class="data" data-tag="bytes" data-xpath="/top/data/bytes">0</div>
<div class="data" data-tag="bytes" data-xpath="/top/data[name = 'em0 '][name = 'em0']/bytes">0</div>
<div class="padding"> </div>
<div class="note">bytes</div>
</div>
<div class="line">
<div class="data" data-tag="bytes" data-xpath="/top/data/bytes">1</div>
<div class="data" data-tag="bytes" data-xpath="/top/data[name = 'em0 '][name = 'em0']/bytes">1</div>
<div class="padding"> </div>
<div class="note">byte</div>
</div>
<div class="line">
<div class="data" data-tag="bytes" data-xpath="/top/data/bytes">2</div>
<div class="data" data-tag="bytes" data-xpath="/top/data[name = 'em0 '][name = 'em0']/bytes">2</div>
<div class="padding"> </div>
<div class="note">bytes</div>
</div>
<div class="line">
<div class="data" data-tag="bytes" data-xpath="/top/data/bytes">3</div>
<div class="data" data-tag="bytes" data-xpath="/top/data[name = 'em0 '][name = 'em0']/bytes">3</div>
<div class="padding"> </div>
<div class="note">bytes</div>
</div>
<div class="line">
<div class="data" data-tag="bytes" data-xpath="/top/data/bytes">4</div>
<div class="data" data-tag="bytes" data-xpath="/top/data[name = 'em0 '][name = 'em0']/bytes">4</div>
<div class="padding"> </div>
<div class="note">bytes</div>
</div>
<div class="line">
<div class="data" data-tag="mbuf-current" data-xpath="/top/data/mbuf-current">10</div>
<div class="data" data-tag="mbuf-current" data-xpath="/top/data[name = 'em0 '][name = 'em0']/mbuf-current">10</div>
<div class="text">/</div>
<div class="data" data-tag="mbuf-cache" data-xpath="/top/data/mbuf-cache">20</div>
<div class="data" data-tag="mbuf-cache" data-xpath="/top/data[name = 'em0 '][name = 'em0']/mbuf-cache">20</div>
<div class="text">/</div>
<div class="data" data-tag="mbuf-total" data-xpath="/top/data/mbuf-total">30</div>
<div class="data" data-tag="mbuf-total" data-xpath="/top/data[name = 'em0 '][name = 'em0']/mbuf-total">30</div>
<div class="text"> </div>
<div class="note">mbufs &lt;&amp;&gt; in use (current/cache/total)</div>
</div>
<div class="line">
<div class="data" data-tag="distance" data-units="miles" data-xpath="/top/data/distance">50</div>
<div class="data" data-tag="distance" data-units="miles" data-xpath="/top/data[name = 'em0 '][name = 'em0']/distance">50</div>
<div class="padding"> </div>
<div class="text"> from </div>
<div class="data" data-tag="location" data-xpath="/top/data/location">Boston</div>
<div class="data" data-tag="location" data-xpath="/top/data[name = 'em0 '][name = 'em0']/location">Boston</div>
</div>
<div class="line">
<div class="data" data-tag="memory" data-units="k" data-xpath="/top/data/memory">64</div>
<div class="data" data-tag="memory" data-units="k" data-xpath="/top/data[name = 'em0 '][name = 'em0']/memory">64</div>
<div class="text"> left out of </div>
<div class="data" data-tag="total" data-units="kb" data-xpath="/top/data/total">640</div>
<div class="data" data-tag="total" data-units="kb" data-xpath="/top/data[name = 'em0 '][name = 'em0']/total">640</div>
</div>
<div class="line">
<div class="data" data-tag="memory" data-units="k" data-xpath="/top/data/memory">64</div>
<div class="data" data-tag="memory" data-units="k" data-xpath="/top/data[name = 'em0 '][name = 'em0']/memory">64</div>
<div class="text"> left out of </div>
<div class="data" data-tag="total" data-units="kilobytes" data-xpath="/top/data/total">640</div>
<div class="data" data-tag="total" data-units="kilobytes" data-xpath="/top/data[name = 'em0 '][name = 'em0']/total">640</div>
</div>
<div class="line">
<div class="title">beforeworkingafter:</div>
</div>
<div class="line">
<div class="data" data-tag="some" data-xpath="/top/data/some">string</div>
<div class="data" data-tag="some" data-xpath="/top/data[name = 'em0 '][name = 'em0']/some">string</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="ten" data-xpath="/top/data/ten">10</div>
<div class="data" data-tag="eleven" data-xpath="/top/data/eleven">11</div>
<div class="data" data-tag="ten" data-xpath="/top/data[name = 'em0 '][name = 'em0']/ten">10</div>
<div class="data" data-tag="eleven" data-xpath="/top/data[name = 'em0 '][name = 'em0']/eleven">11</div>
</div>
<div class="line">
<div class="data" data-tag="unknown" data-xpath="/top/data/unknown">1010</div>
<div class="data" data-tag="unknown" data-xpath="/top/data[name = 'em0 '][name = 'em0']/unknown">1010</div>
<div class="text"> </div>
<div class="note">packets here/there/everywhere</div>
</div>
<div class="line">
<div class="data" data-tag="unknown" data-xpath="/top/data/unknown">1010</div>
<div class="data" data-tag="unknown" data-xpath="/top/data[name = 'em0 '][name = 'em0']/unknown">1010</div>
<div class="text"> </div>
<div class="note">packets here/there/everywhere</div>
</div>
<div class="line">
<div class="text">(</div>
<div class="padding"> </div>
<div class="data" data-tag="min" data-xpath="/top/data/min">15</div>
<div class="data" data-tag="min" data-xpath="/top/data[name = 'em0 '][name = 'em0']/min">15</div>
<div class="text">/</div>
<div class="data" data-tag="cur" data-xpath="/top/data/cur">20</div>
<div class="data" data-tag="cur" data-xpath="/top/data[name = 'em0 '][name = 'em0']/cur">20</div>
<div class="text">/</div>
<div class="data" data-tag="max" data-xpath="/top/data/max">125</div>
<div class="data" data-tag="max" data-xpath="/top/data[name = 'em0 '][name = 'em0']/max">125</div>
<div class="text">)</div>
</div>
<div class="line">
<div class="text">(</div>
<div class="padding"> </div>
<div class="data" data-tag="min" data-xpath="/top/data/min">15</div>
<div class="data" data-tag="min" data-xpath="/top/data[name = 'em0 '][name = 'em0']/min">15</div>
<div class="text">/</div>
<div class="data" data-tag="cur" data-xpath="/top/data/cur">20</div>
<div class="data" data-tag="cur" data-xpath="/top/data[name = 'em0 '][name = 'em0']/cur">20</div>
<div class="text">/</div>
<div class="data" data-tag="max" data-xpath="/top/data/max">125</div>
<div class="data" data-tag="max" data-xpath="/top/data[name = 'em0 '][name = 'em0']/max">125</div>
<div class="text">)</div>
</div>
<div class="line">
<div class="text">(</div>
<div class="data" data-tag="min" data-xpath="/top/data/min">15</div>
<div class="data" data-tag="min" data-xpath="/top/data[name = 'em0 '][name = 'em0']/min">15</div>
<div class="text">/</div>
<div class="data" data-tag="cur" data-xpath="/top/data/cur">20</div>
<div class="data" data-tag="cur" data-xpath="/top/data[name = 'em0 '][name = 'em0']/cur">20</div>
<div class="text">/</div>
<div class="data" data-tag="max" data-xpath="/top/data/max">125</div>
<div class="data" data-tag="max" data-xpath="/top/data[name = 'em0 '][name = 'em0']/max">125</div>
<div class="padding"> </div>
<div class="text">)</div>
</div>
<div class="line">
<div class="text">(</div>
<div class="data" data-tag="min" data-xpath="/top/data/min">15</div>
<div class="data" data-tag="min" data-xpath="/top/data[name = 'em0 '][name = 'em0']/min">15</div>
<div class="text">/</div>
<div class="data" data-tag="cur" data-xpath="/top/data/cur">20</div>
<div class="data" data-tag="cur" data-xpath="/top/data[name = 'em0 '][name = 'em0']/cur">20</div>
<div class="text">/</div>
<div class="data" data-tag="max" data-xpath="/top/data/max">125</div>
<div class="data" data-tag="max" data-xpath="/top/data[name = 'em0 '][name = 'em0']/max">125</div>
<div class="padding"> </div>
<div class="text">)</div>
</div>
<div class="line">
<div class="text">Humanize: </div>
<div class="data" data-tag="val1" data-xpath="/top/data/val1" data-number="21">21</div>
<div class="data" data-tag="val1" data-xpath="/top/data[name = 'em0 '][name = 'em0']/val1" data-number="21">21</div>
<div class="text">, </div>
<div class="data" data-tag="val2" data-xpath="/top/data/val2" data-number="58368">57 K</div>
<div class="data" data-tag="val2" data-xpath="/top/data[name = 'em0 '][name = 'em0']/val2" data-number="58368">57 K</div>
<div class="text">, </div>
<div class="data" data-tag="val3" data-xpath="/top/data/val3" data-number="100663296">96M</div>
<div class="data" data-tag="val3" data-xpath="/top/data[name = 'em0 '][name = 'em0']/val3" data-number="100663296">96M</div>
<div class="text">, </div>
<div class="data" data-tag="val4" data-xpath="/top/data/val4" data-number="44470272">44M</div>
<div class="data" data-tag="val4" data-xpath="/top/data[name = 'em0 '][name = 'em0']/val4" data-number="44470272">44M</div>
<div class="text">, </div>
<div class="data" data-tag="val5" data-xpath="/top/data/val5" data-number="1342172800">1.2G</div>
<div class="data" data-tag="val5" data-xpath="/top/data[name = 'em0 '][name = 'em0']/val5" data-number="1342172800">1.2G</div>
</div>
<div class="line">
<div class="data" data-tag="flag" data-xpath="/top/data/flag">one</div>
<div class="data" data-tag="flag" data-xpath="/top/data[name = 'em0 '][name = 'em0']/flag">one</div>
<div class="text"> </div>
<div class="data" data-tag="flag" data-xpath="/top/data/flag">two</div>
<div class="data" data-tag="flag" data-xpath="/top/data[name = 'em0 '][name = 'em0']/flag">two</div>
<div class="text"> </div>
<div class="data" data-tag="flag" data-xpath="/top/data/flag">three</div>
<div class="data" data-tag="flag" data-xpath="/top/data[name = 'em0 '][name = 'em0']/flag">three</div>
</div>
<div class="line">
<div class="data" data-tag="works" data-xpath="/top/data/works">(null)</div>
<div class="data" data-tag="works" data-xpath="/top/data[name = 'em0 '][name = 'em0']/works">(null)</div>
</div>
<div class="line">
<div class="text">1:</div>
<div class="data" data-tag="t1" data-xpath="/top/data/t1"> 1000</div>
<div class="data" data-tag="t1" data-xpath="/top/data[name = 'em0 '][name = 'em0']/t1"> 1000</div>
<div class="text"> 2:</div>
<div class="data" data-tag="t2" data-xpath="/top/data/t2">test5000 </div>
<div class="data" data-tag="t2" data-xpath="/top/data[name = 'em0 '][name = 'em0']/t2">test5000 </div>
<div class="text"> 3:</div>
<div class="data" data-tag="t3" data-xpath="/top/data/t3"> ten-longx</div>
<div class="data" data-tag="t3" data-xpath="/top/data[name = 'em0 '][name = 'em0']/t3"> ten-longx</div>
<div class="text"> 4:</div>
<div class="data" data-tag="t4" data-xpath="/top/data/t4">xtest </div>
<div class="data" data-tag="t4" data-xpath="/top/data[name = 'em0 '][name = 'em0']/t4">xtest </div>
</div>
<div class="line">
<div class="error">this is an error</div>
@ -208,10 +210,10 @@
<div class="line">
<div class="label">V1/V2 packets</div>
<div class="text">: </div>
<div class="data" data-tag="count" data-xpath="/top/data/count">10</div>
<div class="data" data-tag="count" data-xpath="/top/data[name = 'em0 '][name = 'em0']/count">10</div>
</div>
<div class="line">
<div class="data" data-tag="test" data-xpath="/top/data/test">0004</div>
<div class="data" data-tag="test" data-xpath="/top/data[name = 'em0 '][name = 'em0']/test">0004</div>
<div class="text"> </div>
<div class="label">tries</div>
</div>

View File

@ -0,0 +1 @@
test_02: key field emitted after normal value field: 'name'

View File

@ -1,4 +1,6 @@
<div class="line">
<div class="data" data-tag="name">em0 </div>
<div class="data">em0 </div>
<div class="text">We are </div>
<div class="text">{emit}</div>
<div class="text">{ting}</div>

View File

@ -0,0 +1 @@
test_02: key field emitted after normal value field: 'name'

View File

@ -1 +1 @@
{"top": {"data": {"what":"braces","length":"abcdef","fd":-1,"error":"Bad file descriptor","test":"good","fd":-1,"error":"Bad fi","test":"good","lines":20,"words":30,"characters":40, "bytes": [0,1,2,3,4],"mbuf-current":10,"mbuf-cache":20,"mbuf-total":30,"distance":50,"location":"Boston","memory":64,"total":640,"memory":64,"total":640,"ten":10,"eleven":11,"unknown":1010,"unknown":1010,"min":15,"cur":20,"max":125,"min":15,"cur":20,"max":125,"min":15,"cur":20,"max":125,"min":15,"cur":20,"max":125,"val1":21,"val2":58368,"val3":100663296,"val4":44470272,"val5":1342172800, "flag": ["one","two","three"],"works":null,"empty-tag":true,"t1":"1000","t2":"test5000","t3":"ten-longx","t4":"xtest", "__error": {"message":"this is an error"}, "__error": {"message":"two more errors"}, "__warning": {"message":"this is an warning"}, "__warning": {"message":"two more warnings"},"count":10,"test":4, "error": {"message":"Shut 'er down, Clancey! She's a-pumpin' mud! <>!,\"!<>\n"}}}}
{"top": {"data": {"name":"em0","flags":"0x8843","name":"em0","flags":"0x8843","what":"braces","length":"abcdef","fd":-1,"error":"Bad file descriptor","test":"good","fd":-1,"error":"Bad fi","test":"good","lines":20,"words":30,"characters":40, "bytes": [0,1,2,3,4],"mbuf-current":10,"mbuf-cache":20,"mbuf-total":30,"distance":50,"location":"Boston","memory":64,"total":640,"memory":64,"total":640,"ten":10,"eleven":11,"unknown":1010,"unknown":1010,"min":15,"cur":20,"max":125,"min":15,"cur":20,"max":125,"min":15,"cur":20,"max":125,"min":15,"cur":20,"max":125,"val1":21,"val2":58368,"val3":100663296,"val4":44470272,"val5":1342172800, "flag": ["one","two","three"],"works":null,"empty-tag":true,"t1":"1000","t2":"test5000","t3":"ten-longx","t4":"xtest", "__error": {"message":"this is an error"}, "__error": {"message":"two more errors"}, "__warning": {"message":"this is an warning"}, "__warning": {"message":"two more warnings"},"count":10,"test":4, "error": {"message":"Shut 'er down, Clancey! She's a-pumpin' mud! <>!,\"!<>\n"}}}}

View File

@ -0,0 +1 @@
test_02: key field emitted after normal value field: 'name'

View File

@ -1,6 +1,10 @@
{
"top": {
"data": {
"name": "em0",
"flags": "0x8843",
"name": "em0",
"flags": "0x8843",
"what": "braces",
"length": "abcdef",
"fd": -1,

View File

@ -1 +1,2 @@
test_02: key field emitted after normal value field: 'name'
Shut 'er down, Clancey! She's a-pumpin' mud! <>!,"!<>

View File

@ -1,4 +1,4 @@
We are {emit}{ting} some braces
em0 em0 We are {emit}{ting} some braces
abcdef
abcdef: Bad file descriptor
improper use of profanity; ten yard penalty; first down

View File

@ -0,0 +1 @@
test_02: key field emitted after normal value field: 'name'

View File

@ -1,4 +1,4 @@
<top><data><what>braces</what><message>abcdef
<top><data><name>em0</name><flags>0x8843</flags><name>em0</name><flags>0x8843</flags><what>braces</what><message>abcdef
</message><message>abcdef: Bad file descriptor
</message><message>improper use of profanity; ten yard penalty; first down
</message><length>abcdef</length><fd>-1</fd><error>Bad file descriptor</error><test>good</test><fd>-1</fd><error>Bad fi</error><test>good</test><message>improper use of profanity; ten yard penalty; first down

View File

@ -0,0 +1 @@
test_02: key field emitted after normal value field: 'name'

View File

@ -1,5 +1,9 @@
<top>
<data>
<name>em0</name>
<flags>0x8843</flags>
<name>em0</name>
<flags>0x8843</flags>
<what>braces</what>
<message>abcdef
</message>

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, Juniper Networks, Inc.
* Copyright (c) 2014-2019, Juniper Networks, Inc.
* All rights reserved.
* This SOFTWARE is licensed under the LICENSE provided in the
* ../Copyright file. By downloading, installing, copying, or otherwise

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, Juniper Networks, Inc.
* Copyright (c) 2014-2019, Juniper Networks, Inc.
* All rights reserved.
* This SOFTWARE is licensed under the LICENSE provided in the
* ../Copyright file. By downloading, installing, copying, or otherwise
@ -48,6 +48,12 @@ main (int argc, char **argv)
xo_open_container("data");
xo_emit("{kt:name/%-*.*s}{eq:flags/0x%x}",
5, 5, "em0", 34883);
xo_emit("{d:/%-*.*s}{etk:name}{eq:flags/0x%x}",
5, 5, "em0", "em0", 34883);
xo_emit("We are {{emit}}{{ting}} some {:what}\n", "braces");
xo_message("abcdef");

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014-2018, Juniper Networks, Inc.
* Copyright (c) 2014-2019, Juniper Networks, Inc.
* All rights reserved.
* This SOFTWARE is licensed under the LICENSE provided in the
* ../Copyright file. By downloading, installing, copying, or otherwise

View File

@ -1984,32 +1984,10 @@ ARMTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
// Build a sequence of copy-to-reg nodes chained together with token chain
// and flag operands which copy the outgoing args into the appropriate regs.
SDValue InFlag;
// Tail call byval lowering might overwrite argument registers so in case of
// tail call optimization the copies to registers are lowered later.
if (!isTailCall)
for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) {
Chain = DAG.getCopyToReg(Chain, dl, RegsToPass[i].first,
RegsToPass[i].second, InFlag);
InFlag = Chain.getValue(1);
}
// For tail calls lower the arguments to the 'real' stack slot.
if (isTailCall) {
// Force all the incoming stack arguments to be loaded from the stack
// before any new outgoing arguments are stored to the stack, because the
// outgoing stack slots may alias the incoming argument stack slots, and
// the alias isn't otherwise explicit. This is slightly more conservative
// than necessary, because it means that each store effectively depends
// on every argument instead of just those arguments it would clobber.
// Do not flag preceding copytoreg stuff together with the following stuff.
InFlag = SDValue();
for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) {
Chain = DAG.getCopyToReg(Chain, dl, RegsToPass[i].first,
RegsToPass[i].second, InFlag);
InFlag = Chain.getValue(1);
}
InFlag = SDValue();
for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) {
Chain = DAG.getCopyToReg(Chain, dl, RegsToPass[i].first,
RegsToPass[i].second, InFlag);
InFlag = Chain.getValue(1);
}
// If the callee is a GlobalAddress/ExternalSymbol node (quite common, every

View File

@ -1,4 +1,4 @@
$Id: INSTALL,v 1.22 2018/07/31 15:34:00 schwarze Exp $
$Id: INSTALL,v 1.23 2019/03/06 15:58:10 schwarze Exp $
About the portable mandoc distribution
--------------------------------------
@ -18,7 +18,7 @@ tech@ mailing list, too.
Enjoy using the mandoc toolset!
Ingo Schwarze, Karlsruhe, August 2018
Ingo Schwarze, Karlsruhe, March 2019
Installation
@ -67,7 +67,8 @@ variables into "configure.local" and go back to step 4.
7. Optionally run the regression suite.
Basically, that amounts to "cd regress && ./regress.pl".
But you should probably look at "./mandoc -l regress/regress.pl.1"
first.
first. In particular, regarding Solaris systems, look at the BUGS
section of that manual page.
8. Run "sudo make install". If you intend to build a binary
package using some kind of fake root mechanism, you may need a

View File

@ -1,8 +1,8 @@
$Id: LICENSE,v 1.19 2018/07/31 10:18:15 schwarze Exp $
$Id: LICENSE,v 1.21 2018/11/26 17:11:11 schwarze Exp $
With the exceptions noted below, all code and documentation
contained in the mandoc toolkit is protected by the Copyright
of the following developers:
With the exceptions noted below, all non-trivial files contained
in the mandoc toolkit are protected by the Copyright of the following
developers:
Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
Copyright (c) 2010-2018 Ingo Schwarze <schwarze@openbsd.org>
@ -12,13 +12,14 @@ Copyright (c) 2013 Franco Fichtner <franco@lastsummer.de>
Copyright (c) 2014 Baptiste Daroussin <bapt@freebsd.org>
Copyright (c) 2016 Ed Maste <emaste@freebsd.org>
Copyright (c) 2017 Michael Stapelberg <stapelberg@debian.org>
Copyright (c) 2017 Anthony Bentley <bentley@openbsd.org>
Copyright (c) 1998, 2004, 2010 Todd C. Miller <Todd.Miller@courtesan.com>
Copyright (c) 2008, 2017 Otto Moerbeek <otto@drijf.net>
Copyright (c) 2004 Ted Unangst <tedu@openbsd.org>
Copyright (c) 1994 Christos Zoulas <christos@netbsd.org>
Copyright (c) 2003, 2007, 2008, 2014 Jason McIntyre <jmc@openbsd.org>
See the individual source files for information about who contributed
See the individual files for information about who contributed
to which file during which years.

View File

@ -1,7 +1,7 @@
# $Id: Makefile,v 1.519 2018/07/31 15:34:00 schwarze Exp $
# $Id: Makefile,v 1.530 2019/03/06 16:08:41 schwarze Exp $
#
# Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
# Copyright (c) 2011, 2013-2018 Ingo Schwarze <schwarze@openbsd.org>
# Copyright (c) 2011, 2013-2019 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
@ -15,7 +15,7 @@
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
VERSION = 1.14.4
VERSION = 1.14.5
# === LIST OF FILES ====================================================
@ -37,9 +37,9 @@ TESTSRCS = test-be32toh.c \
test-PATH_MAX.c \
test-pledge.c \
test-progname.c \
test-recvmsg.c \
test-reallocarray.c \
test-recallocarray.c \
test-recvmsg.c \
test-rewb-bsd.c \
test-rewb-sysv.c \
test-sandbox_init.c \
@ -54,7 +54,8 @@ TESTSRCS = test-be32toh.c \
test-vasprintf.c \
test-wchar.c
SRCS = att.c \
SRCS = arch.c \
att.c \
catman.c \
cgi.c \
chars.c \
@ -96,6 +97,7 @@ SRCS = att.c \
man_validate.c \
mandoc.c \
mandoc_aux.c \
mandoc_msg.c \
mandoc_ohash.c \
mandoc_xr.c \
mandocd.c \
@ -155,13 +157,14 @@ DISTFILES = INSTALL \
dbm_map.h \
demandoc.1 \
eqn.7 \
eqn.h \
eqn_parse.h \
gmdiff \
html.h \
lib.in \
libman.h \
libmandoc.h \
libmdoc.h \
libroff.h \
main.h \
makewhatis.8 \
man.1 \
@ -184,6 +187,7 @@ DISTFILES = INSTALL \
mandoc_html.3 \
mandoc_malloc.3 \
mandoc_ohash.h \
mandoc_parse.h \
mandoc_xr.h \
mandocd.8 \
mansearch.3 \
@ -198,10 +202,12 @@ DISTFILES = INSTALL \
roff.h \
roff_int.h \
soelim.1 \
st.in \
tag.h \
tbl.3 \
tbl.7 \
tbl.h \
tbl_int.h \
tbl_parse.h \
term.h \
$(SRCS) \
$(TESTSRCS)
@ -230,9 +236,11 @@ LIBROFF_OBJS = eqn.o \
LIBMANDOC_OBJS = $(LIBMAN_OBJS) \
$(LIBMDOC_OBJS) \
$(LIBROFF_OBJS) \
arch.o \
chars.o \
mandoc.o \
mandoc_aux.o \
mandoc_msg.o \
mandoc_ohash.o \
mandoc_xr.o \
msec.o \
@ -320,6 +328,7 @@ SOELIM_OBJS = soelim.o \
WWW_MANS = apropos.1.html \
demandoc.1.html \
man.1.html \
man.options.1.html \
mandoc.1.html \
soelim.1.html \
man.cgi.3.html \
@ -336,20 +345,27 @@ WWW_MANS = apropos.1.html \
eqn.7.html \
man.7.html \
mandoc_char.7.html \
mandocd.8.html \
mdoc.7.html \
roff.7.html \
tbl.7.html \
catman.8.html \
makewhatis.8.html \
man.cgi.8.html \
mandocd.8.html
WWW_INCS = eqn.h.html \
html.h.html \
man.h.html \
manconf.h.html \
mandoc.h.html \
mandoc_aux.h.html \
mandoc_parse.h.html \
mansearch.h.html \
mdoc.h.html \
roff.h.html
roff.h.html \
tbl.h.html \
tbl_int.h.html \
tbl_parse.h.html
# === USER CONFIGURATION ===============================================
@ -361,9 +377,9 @@ all: mandoc demandoc soelim $(BUILD_TARGETS) Makefile.local
install: base-install $(INSTALL_TARGETS)
www: $(WWW_MANS)
www: $(WWW_MANS) $(WWW_INCS)
$(WWW_MANS): mandoc
$(WWW_MANS) $(WWW_INCS): mandoc
.PHONY: base-install cgi-install install www-install
.PHONY: clean distclean depend
@ -382,7 +398,7 @@ clean:
rm -f mandocd catman catman.o $(MANDOCD_OBJS)
rm -f demandoc $(DEMANDOC_OBJS)
rm -f soelim $(SOELIM_OBJS)
rm -f $(WWW_MANS) mandoc.tar.gz mandoc.sha256
rm -f $(WWW_MANS) $(WWW_INCS) mandoc*.tar.gz mandoc*.sha256
rm -rf *.dSYM
base-install: mandoc demandoc soelim
@ -420,8 +436,8 @@ lib-install: libmandoc.a
mkdir -p $(DESTDIR)$(INCLUDEDIR)
mkdir -p $(DESTDIR)$(MANDIR)/man3
$(INSTALL_LIB) libmandoc.a $(DESTDIR)$(LIBDIR)
$(INSTALL_LIB) man.h mandoc.h mandoc_aux.h mdoc.h roff.h \
$(DESTDIR)$(INCLUDEDIR)
$(INSTALL_LIB) eqn.h man.h mandoc.h mandoc_aux.h mandoc_parse.h \
mdoc.h roff.h tbl.h $(DESTDIR)$(INCLUDEDIR)
$(INSTALL_MAN) mandoc.3 mandoc_escape.3 mandoc_malloc.3 \
mansearch.3 mchars_alloc.3 tbl.3 $(DESTDIR)$(MANDIR)/man3
@ -475,11 +491,14 @@ uninstall:
rm -f $(DESTDIR)$(MANDIR)/man3/mansearch.3
rm -f $(DESTDIR)$(MANDIR)/man3/mchars_alloc.3
rm -f $(DESTDIR)$(MANDIR)/man3/tbl.3
rm -f $(DESTDIR)$(INCLUDEDIR)/eqn.h
rm -f $(DESTDIR)$(INCLUDEDIR)/man.h
rm -f $(DESTDIR)$(INCLUDEDIR)/mandoc.h
rm -f $(DESTDIR)$(INCLUDEDIR)/mandoc_aux.h
rm -f $(DESTDIR)$(INCLUDEDIR)/mandoc_parse.h
rm -f $(DESTDIR)$(INCLUDEDIR)/mdoc.h
rm -f $(DESTDIR)$(INCLUDEDIR)/roff.h
rm -f $(DESTDIR)$(INCLUDEDIR)/tbl.h
[ ! -e $(DESTDIR)$(INCLUDEDIR) ] || rmdir $(DESTDIR)$(INCLUDEDIR)
regress: all
@ -516,7 +535,9 @@ soelim: $(SOELIM_OBJS)
# --- maintainer targets ---
www-install: www
$(INSTALL_DATA) $(WWW_MANS) mandoc.css $(HTDOCDIR)
$(INSTALL_DATA) mandoc.css $(HTDOCDIR)
$(INSTALL_DATA) $(WWW_MANS) $(HTDOCDIR)/man
$(INSTALL_DATA) $(WWW_INCS) $(HTDOCDIR)/includes
depend: config.h
mkdep -f Makefile.depend $(CFLAGS) $(SRCS)
@ -564,6 +585,10 @@ mandoc-$(VERSION).tar.gz: $(DISTFILES)
( cd .dist/ && tar zcf ../$@ mandoc-$(VERSION) )
rm -rf .dist/
dist-install: dist
$(INSTALL_DATA) mandoc-$(VERSION).tar.gz mandoc-$(VERSION).sha256 \
$(HTDOCDIR)/snapshots
# === SUFFIX RULES =====================================================
.SUFFIXES: .1 .3 .5 .7 .8 .h
@ -573,5 +598,6 @@ mandoc-$(VERSION).tar.gz: $(DISTFILES)
highlight -I $< > $@
.1.1.html .3.3.html .5.5.html .7.7.html .8.8.html: mandoc
./mandoc -Thtml -Wall,stop \
-Ostyle=mandoc.css,man=%N.%S.html,includes=%I.html $< > $@
mandoc -Thtml -Wwarning,stop \
-O 'style=/mandoc.css,man=/man/%N.%S.html;https://man.openbsd.org/%N.%S,includes=/includes/%I.html' \
$< > $@

View File

@ -1,6 +1,7 @@
att.o: att.c config.h mandoc.h roff.h mdoc.h libmdoc.h
arch.o: arch.c config.h roff.h
att.o: att.c config.h roff.h libmdoc.h
catman.o: catman.c config.h compat_fts.h
cgi.o: cgi.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h man.h main.h manconf.h mansearch.h cgi.h
cgi.o: cgi.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h man.h mandoc_parse.h main.h manconf.h mansearch.h cgi.h
chars.o: chars.c config.h mandoc.h mandoc_aux.h mandoc_ohash.h compat_ohash.h libmandoc.h
compat_err.o: compat_err.c config.h
compat_fts.o: compat_fts.c config.h compat_fts.h
@ -26,54 +27,55 @@ dba_read.o: dba_read.c mandoc_aux.h mansearch.h dba_array.h dba.h dbm.h
dba_write.o: dba_write.c config.h dba_write.h
dbm.o: dbm.c config.h mansearch.h dbm_map.h dbm.h
dbm_map.o: dbm_map.c config.h mansearch.h dbm_map.h dbm.h
demandoc.o: demandoc.c config.h mandoc.h roff.h man.h mdoc.h
eqn.o: eqn.c config.h mandoc_aux.h mandoc.h roff.h libmandoc.h libroff.h
eqn_html.o: eqn_html.c config.h mandoc.h out.h html.h
eqn_term.o: eqn_term.c config.h mandoc.h out.h term.h
demandoc.o: demandoc.c config.h mandoc.h roff.h man.h mdoc.h mandoc_parse.h
eqn.o: eqn.c config.h mandoc_aux.h mandoc.h roff.h eqn.h libmandoc.h eqn_parse.h
eqn_html.o: eqn_html.c config.h mandoc.h eqn.h out.h html.h
eqn_term.o: eqn_term.c config.h eqn.h out.h term.h
html.o: html.c config.h mandoc_aux.h mandoc_ohash.h compat_ohash.h mandoc.h roff.h out.h html.h manconf.h main.h
lib.o: lib.c config.h mandoc.h roff.h mdoc.h libmdoc.h lib.in
main.o: main.c config.h mandoc_aux.h mandoc.h mandoc_xr.h roff.h mdoc.h man.h tag.h main.h manconf.h mansearch.h
lib.o: lib.c config.h roff.h libmdoc.h lib.in
main.o: main.c config.h mandoc_aux.h mandoc.h mandoc_xr.h roff.h mdoc.h man.h mandoc_parse.h tag.h main.h manconf.h mansearch.h
man.o: man.c config.h mandoc_aux.h mandoc.h roff.h man.h libmandoc.h roff_int.h libman.h
man_html.o: man_html.c config.h mandoc_aux.h mandoc.h roff.h man.h out.h html.h main.h
man_macro.o: man_macro.c config.h mandoc.h roff.h man.h libmandoc.h roff_int.h libman.h
man_term.o: man_term.c config.h mandoc_aux.h mandoc.h roff.h man.h out.h term.h main.h
man_term.o: man_term.c config.h mandoc_aux.h roff.h man.h out.h term.h main.h
man_validate.o: man_validate.c config.h mandoc_aux.h mandoc.h roff.h man.h libmandoc.h roff_int.h libman.h
mandoc.o: mandoc.c config.h mandoc_aux.h mandoc.h roff.h libmandoc.h
mandoc.o: mandoc.c config.h mandoc_aux.h mandoc.h roff.h libmandoc.h roff_int.h
mandoc_aux.o: mandoc_aux.c config.h mandoc.h mandoc_aux.h
mandoc_msg.o: mandoc_msg.c mandoc.h
mandoc_ohash.o: mandoc_ohash.c mandoc_aux.h mandoc_ohash.h compat_ohash.h
mandoc_xr.o: mandoc_xr.c mandoc_aux.h mandoc_ohash.h compat_ohash.h mandoc_xr.h
mandocd.o: mandocd.c config.h mandoc.h roff.h mdoc.h man.h main.h manconf.h
mandocdb.o: mandocdb.c config.h compat_fts.h mandoc_aux.h mandoc_ohash.h compat_ohash.h mandoc.h roff.h mdoc.h man.h manconf.h mansearch.h dba_array.h dba.h
mandocd.o: mandocd.c config.h mandoc.h roff.h mdoc.h man.h mandoc_parse.h main.h manconf.h
mandocdb.o: mandocdb.c config.h compat_fts.h mandoc_aux.h mandoc_ohash.h compat_ohash.h mandoc.h roff.h mdoc.h man.h mandoc_parse.h manconf.h mansearch.h dba_array.h dba.h
manpath.o: manpath.c config.h mandoc_aux.h manconf.h
mansearch.o: mansearch.c config.h mandoc.h mandoc_aux.h mandoc_ohash.h compat_ohash.h manconf.h mansearch.h dbm.h
mansearch.o: mansearch.c config.h mandoc_aux.h mandoc_ohash.h compat_ohash.h manconf.h mansearch.h dbm.h
mdoc.o: mdoc.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h
mdoc_argv.o: mdoc_argv.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h
mdoc_html.o: mdoc_html.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h out.h html.h main.h
mdoc_macro.o: mdoc_macro.c config.h mandoc.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h
mdoc_man.o: mdoc_man.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h man.h out.h main.h
mdoc_markdown.o: mdoc_markdown.c mandoc_aux.h mandoc.h roff.h mdoc.h main.h
mdoc_state.o: mdoc_state.c mandoc.h roff.h mdoc.h libmandoc.h libmdoc.h
mdoc_term.o: mdoc_term.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h out.h term.h tag.h main.h
mdoc_state.o: mdoc_state.c mandoc.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h
mdoc_term.o: mdoc_term.c config.h mandoc_aux.h roff.h mdoc.h out.h term.h tag.h main.h
mdoc_validate.o: mdoc_validate.c config.h mandoc_aux.h mandoc.h mandoc_xr.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h
msec.o: msec.c config.h mandoc.h libmandoc.h msec.in
out.o: out.c config.h mandoc_aux.h mandoc.h out.h
preconv.o: preconv.c config.h mandoc.h libmandoc.h
read.o: read.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h man.h libmandoc.h
roff.o: roff.c config.h mandoc.h mandoc_aux.h mandoc_ohash.h compat_ohash.h roff.h libmandoc.h roff_int.h libroff.h predefs.in
out.o: out.c config.h mandoc_aux.h tbl.h out.h
preconv.o: preconv.c config.h mandoc.h roff.h mandoc_parse.h libmandoc.h
read.o: read.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h man.h mandoc_parse.h libmandoc.h roff_int.h
roff.o: roff.c config.h mandoc_aux.h mandoc_ohash.h compat_ohash.h mandoc.h roff.h mandoc_parse.h libmandoc.h roff_int.h tbl_parse.h eqn_parse.h predefs.in
roff_html.o: roff_html.c mandoc.h roff.h out.h html.h
roff_term.o: roff_term.c mandoc.h roff.h out.h term.h
roff_validate.o: roff_validate.c mandoc.h roff.h libmandoc.h roff_int.h
soelim.o: soelim.c config.h compat_stringlist.h
st.o: st.c config.h mandoc.h roff.h mdoc.h libmdoc.h st.in
st.o: st.c config.h mandoc.h roff.h libmdoc.h
tag.o: tag.c config.h mandoc_aux.h mandoc_ohash.h compat_ohash.h tag.h
tbl.o: tbl.c config.h mandoc.h mandoc_aux.h libmandoc.h libroff.h
tbl_data.o: tbl_data.c config.h mandoc.h mandoc_aux.h libmandoc.h libroff.h
tbl_html.o: tbl_html.c config.h mandoc.h out.h html.h
tbl_layout.o: tbl_layout.c config.h mandoc.h mandoc_aux.h libmandoc.h libroff.h
tbl_opts.o: tbl_opts.c config.h mandoc.h libmandoc.h libroff.h
tbl_term.o: tbl_term.c config.h mandoc.h out.h term.h
tbl.o: tbl.c config.h mandoc_aux.h mandoc.h tbl.h libmandoc.h tbl_parse.h tbl_int.h
tbl_data.o: tbl_data.c config.h mandoc_aux.h mandoc.h tbl.h libmandoc.h tbl_int.h
tbl_html.o: tbl_html.c config.h mandoc.h tbl.h out.h html.h
tbl_layout.o: tbl_layout.c config.h mandoc_aux.h mandoc.h tbl.h libmandoc.h tbl_int.h
tbl_opts.o: tbl_opts.c config.h mandoc.h tbl.h libmandoc.h tbl_int.h
tbl_term.o: tbl_term.c config.h mandoc.h tbl.h out.h term.h
term.o: term.c config.h mandoc.h mandoc_aux.h out.h term.h main.h
term_ascii.o: term_ascii.c config.h mandoc.h mandoc_aux.h out.h term.h manconf.h main.h
term_ps.o: term_ps.c config.h mandoc_aux.h out.h term.h manconf.h main.h
term_tab.o: term_tab.c mandoc_aux.h out.h term.h
tree.o: tree.c config.h mandoc.h roff.h mdoc.h man.h main.h
tree.o: tree.c config.h mandoc.h roff.h mdoc.h man.h tbl.h eqn.h main.h

View File

@ -1,7 +1,81 @@
$Id: NEWS,v 1.32 2018/08/08 14:47:38 schwarze Exp $
$Id: NEWS,v 1.34 2019/03/10 09:32:00 schwarze Exp $
This file lists the most important changes in the mandoc.bsd.lv distribution.
Changes in version 1.14.5, released on March 10, 2019
--- MAJOR NEW FEATURES ---
* apropos(1): improve POSIX compliance by accepting case-insensitive
extended regular expressions by default
* new -O tag[=term] output option (open a page at the definition of a term)
* tbl(7) -T html: spanning and horizontal and vertical alignment of cells
* tbl(7) -T html: draw lines on the edges of table cells
* tbl(7) -T utf8: render lines with the Unicode box drawing characters
* mandoc is now able to handle the manual pages of the groff package.
--- MINOR NEW FEATURES ---
* -T html: new option -O toc (table of contents)
* -T html: second argument to -O man to support local and remote links
* mdoc(7) .Bd -centered now fills the text contained in it
* man-ext .SY and .YS macros (synopsis block)
* man-ext .TQ macro (tagged paragraph without vertical space before it)
* tbl(7) \& explicit alignment indicator
* roff(7) .shift, .while, and .return requests
* roff(7) .char request (output glyph definition)
* roff(7) .nop request (no operation)
* roff(7) .ft request: handle the CB, CI, and CR fonts
* roff(7) .if c conditional (character available)
* roff(7) \\$@ escape sequence (insert all macro arguments, quoted)
* roff(7) \*(.T predefined string (interpolate output device name)
* roff(7) \[charNNN] escape sequence (for printable ASCII characters)
* roff(7) \# escape sequence (line continuation with comment)
--- HTML OUTPUT SYNTAX CORRECTIONS ---
* Render .br and \p as <br/>, not as an empty <div>.
* Render .Pp and .PP as <p> and automatically close it when needed.
* Stop writing empty list elements for non-compact .Bl -tag lists.
* Do not put <p> inside <a> if .UR or .MT contain .PP.
* Implement tooltips purely in CSS rather than abusing title= attributes.
--- MINOR FUNCTIONAL IMPROVEMENTS ---
* many improvements to the handling of fill and no-fill mode
* tbl(7): better column widths in the presence of horizontal spans
* several minor improvements to escape sequence handling
* several minor improvements to manual font handling
* portability: autodetect need for _GNU_SOURCE or _OPENBSD_SOURCE
* portability: autodetect whether less(1) supports the -T option
* large numbers of bugfixes of diverse kinds
--- STRUCTURAL IMPROVEMENTS ---
* Disentangle eqn(7) and tbl(7) from other parser header files,
and clean up some parser data structures.
* Substantially simplify error and warning message infrastructure.
--- THANKS TO ---
* John Gardner for crucial help implementing tooltips in CSS.
* Alexander Bluhm, Raphael Graf, Ted Unangst (OpenBSD)
and Daniel Sabogal (Alpine Linux) for patches.
* Anthony Bentley and Jason McIntyre (OpenBSD) for documentation patches,
suggesting new features, bug reports, and useful discussions.
* Kyle Evans and Baptiste Daroussin (FreeBSD) for minor patches.
* Pali Rohar for suggesting multiple new features and for reporting
several bugs and missing features.
* Klemens Nanni (OpenBSD) for suggesting multiple new features.
* Kristaps Dzonsons (bsd.lv), Marc Espie (OpenBSD), Adam Kalisz,
and Laura Morales for suggesting new features.
* Wolfram Schneider and Yuri Pankov (FreeBSD) for reporting missing features.
* Edward Tomasz Napierala (FreeBSD) for suggesting a feature improvement.
* Thomas Klausner (NetBSD) and Sevan Janiyan (SmartOS)
for bug reports and release testing.
* Bryan Steele, Janne Johansson, Kurt Mosiejczuk, Mike Belopuhov, Theo
Buehler, Todd Miller (OpenBSD), Andreas Gustafsson, Christos Zoulas,
Robert Elz (NetBSD), Kurt Jaeger (FreeBSD), Fabio Scotoni, Kelvin
Sherlock, Mark Harris, Orestis Ioannou, Raf Czlonka, and Sean Farrell
for bug reports.
* Ulrich Spoerlein (FreeBSD), Leah Neukirchen (Void Linux),
Matej Cepl (openSUSE), and Jan Stary (MacOS X) for release testing.
* Brian Callahan and Stuart Henderson (OpenBSD) for help
with the OpenBSD groff port.
* Bertrand Garrigues, Branden Robinson, Ralph Corderoy, and Werner
Lemberg (GNU troff) for checking groff patches.
* Scott Cheloha, Theo de Raadt (OpenBSD)
and Natanael Copa (Alpine Linux) for useful discussions.
Changes in version 1.14.4, released on August 8, 2018
--- MAJOR NEW FEATURES ---

View File

@ -1,6 +1,6 @@
************************************************************************
* Official mandoc TODO.
* $Id: TODO,v 1.258 2018/08/06 14:16:30 schwarze Exp $
* $Id: TODO,v 1.289 2019/03/04 13:01:57 schwarze Exp $
************************************************************************
Many issues are annotated for difficulty as follows:
@ -38,18 +38,6 @@ are mere guesses, and some may be wrong.
--- missing roff features ----------------------------------------------
- .nop prints its arguments as text,
see groff(7) for an example
- .ft CB selects constant-width bold font
see groff_out(7) for examples
- \*(.T prints the device being used,
see groff_char(7) for an example
- \[charNN], \[charNNN] prints a single-byte codepoint
see groff_char(7) for examples
- .ad (adjust margins)
.ad l -- adjust left margin only (flush left)
.ad r -- adjust right margin only (flush right)
@ -69,34 +57,11 @@ are mere guesses, and some may be wrong.
reported by brad@ Sat, 15 Jan 2011 15:45:23 -0500
loc *** exist *** algo *** size ** imp *
- .while and .shift
found by jca@ in ratpoison(1) Sun, 30 Jun 2013 12:01:09 +0200
loc * exist ** algo ** size ** imp **
- \w'' improve width measurements
would not be very useful without an expression parser, see below
needed for Tcl_NewStringObj(3) via wiz@ Wed, 5 Mar 2014 22:27:43 +0100
loc ** exist *** algo *** size * imp ***
- \\ in high-level macro arguments
Currently, \\ is expanded in two situations:
1) macro and string definition (roff.c setstrn())
2) macro argument parsing (mandoc.c mandoc_getarg())
For user defined macros, the second happens in time because of ROFF_REPARSE.
But for standard high-level macros, it only happens after entering the
high level parsers, which is too late because the code doesn't get
back to roff.c roff_res() from that point. Because this requires
distinguishing requests, user-defined macros and standard macros
on the roff_res() level, it is hard to solve without the parser reorg.
Found by naddy@ in devel/cutils cobfusc(1) Mon, 16 Feb 2015 19:10:52 +0100
loc *** exist *** algo *** size ** imp *
- check for missing roff escape sequences, implement those that are
trivial even if not usually appearing in manual pages, gracefully
ignore the non-trivial ones, document what they are supposed to do
and what mandoc does instead
loc * exist ** algo * size * imp *
--- missing mdoc features ----------------------------------------------
- .Bl -column .Xo support is missing
@ -112,13 +77,6 @@ are mere guesses, and some may be wrong.
from jmc@ Wed, 14 Jul 2010 18:10:32 +0100
loc * exist *** algo *** size ** imp **
- .Bd -centered implies -filled, not -unfilled, which is not
easy to implement; it requires code similar to .ce, which
we don't have either.
Besides, groff has bug causing text right *before* .Bd -centered
to be centered as well.
loc *** exist *** algo ** size ** imp ** (parser reorg would help)
- .Bd -filled should not be the same as .Bd -ragged, but align both
the left and right margin. In groff, it is implemented in terms
of .ad b, which we don't have either. Found in cksum(1).
@ -174,15 +132,6 @@ are mere guesses, and some may be wrong.
--- missing man features -----------------------------------------------
- .SY and .YS,
used by many groff manual pages
- preserve punctuation following .ME,
see ditroff(7) for an example
- .TQ tagged paragraph continuation,
see groff_diff(7) for examples
- groff_www(7) .MTO and .URL
These macros were used by the GNU grep(1) man page.
The groff_www(7) manual page itself uses them, too.
@ -193,18 +142,10 @@ are mere guesses, and some may be wrong.
--- missing tbl features -----------------------------------------------
- the "s" layout column specifier is used for placement of data
into columns, but ignored during column width calculations
synaptics(4) found by tedu@ Mon, 17 Aug 2015 21:17:42 -0400
loc * exist ** algo *** size * imp **
- vertical centering in cells vertically spanned with ^
pali dot rohar at gmail dot com 16 Jul 2018 13:03:35 +0200
loc * exist *** algo *** size ** imp *
- support .ds requests inside tbl(7) code,
see tbl(1) for an example
- support mdoc(7) and man(7) macros inside tbl(7) code;
probably requires the parser reorg and letting tbl(7)
use roff_node such that macro sets can mix;
@ -212,35 +153,24 @@ are mere guesses, and some may be wrong.
loc *** exist ** algo *** size ** imp ***
- look at the POSIX manuals in the books/man-pages-posix port,
they use some unsupported tbl(7) features.
they use some unsupported tbl(7) features, mostly macros in tbl(7).
loc * exist ** algo ** size ** imp ***
- look what Joerg Schilling manual pages use
Thu, 19 Mar 2015 18:31:48 +0100
- use Unicode U+2500 to U+256C for table borders
in tbl(7) -Tutf-8 output
suggested by bentley@ Tue, 14 Oct 2014 04:10:55 -0600
loc * exist ** algo * size * imp **
- implement horizontal and vertical alignment in HTML output
pali dot rohar at gmail dot com 16 Jul 2018 13:03:35 +0200
loc * exist * algo * size * imp ***
- implement cell spanning in HTML output
pali dot rohar at gmail dot com 16 Jul 2018 13:03:35 +0200
loc * exist * algo ** size ** imp **
- implement table borders in HTML output
pali dot rohar at gmail dot com 16 Jul 2018 13:03:35 +0200
loc * exist * algo ** size ** imp **
--- missing eqn features -----------------------------------------------
- In a matrix, break the output line after each matrix line.
Found in the discussion at CDBUG 2015.
Suggested by Avi Weinstock.
loc * exist * algo * size * imp **
Found in the discussion at CDBUG 2015. Suggested by Avi Weinstock.
This may not be the ideal solution after all: eqn(7) matrices
are lists of columns, so Avi's proposal would show each *column*
on its own *line*, which is likely to cause confusion.
A better solution, but much harder to implement, would be to
actually show the coordinates of column vectors on different
terminal output lines, using the clumnated output facilities
developed for .Bl -tag, .Bl -column, and also used for tbl(7).
loc * exist * algo ** size ** imp **
- The "size" keyword is parsed, but ignored by the formatter.
loc * exist * algo * size * imp *
@ -341,9 +271,6 @@ are mere guesses, and some may be wrong.
* formatting issues: ugly output
************************************************************************
- .UR can nest inside .TP,
see roff(7) for examples
- revisit empty in-line macros
look at the difference between "Em x Em ." and "Sq x Em ."
Carsten Kunze Fri, 12 Dec 2014 00:15:41 +0100
@ -400,6 +327,8 @@ are mere guesses, and some may be wrong.
- a line starting with "\fB something" counts as starting with whitespace
and triggers a line break; found in audio/normalize-mp3(1)
This will become easier once escape sequences are represented
by syntax tree nodes.
loc ** exist * algo ** size * imp **
- formatting /usr/local/man/man1/latex2man.1 with groff and mandoc
@ -421,17 +350,6 @@ are mere guesses, and some may be wrong.
--- HTML issues --------------------------------------------------------
- wrap Sh and Ss content into <div>
Laura Morales <lauretas at mail dot com> 21 Apr 2018 18:10:48 +0200
(Evaluate whether this is really useful and has no adverse
side effects before implementing; if it is possible,
it does seem cleaner.)
loc ** exist ** algo * size * imp ***
- format ".IP *" etc. as <ul> rather than <dl>
https://github.com/Debian/debiman/issues/67
loc ** exist ** algo ** size * imp ***
- .Bf at the beginning of a paragraph inserts a bogus 1ex horizontal
space, see for example random(3). Introduced in
http://mdocml.bsd.lv/cgi-bin/cvsweb/mdoc_html.c.diff?r1=1.91&r2=1.92
@ -558,18 +476,11 @@ are mere guesses, and some may be wrong.
all over mdoc_macro.c and all subtly different.
loc ** exist ** algo ** size ** imp **
- style message about suspicious uses of - vs. \- vs. \(mi
e.g. -1 is likely wrong (from the mdoclint TODO)
- warn about punctuation - e.g. ',' and ';' - at the beginning
of a text line, if it is likely intended to follow the preceding
output without intervening whitespace, in particular after a
macro line (from the mdoclint TODO)
- mandoc_special does not really check the escape sequence,
but just the overall format
loc ** exist ** algo *** size ** imp **
- makewhatis -p complains about language subdirectories:
/usr/local/man//ru: Unknown directory part
@ -578,9 +489,6 @@ are mere guesses, and some may be wrong.
* documentation issues
************************************************************************
- dashes, hyphens, and minus signs in manual pages
jmc@ Fri, 28 Mar 2014 07:19:27 +0000
- mark macros as: page structure domain, manual domain, general text domain
is this useful?
@ -606,10 +514,6 @@ are mere guesses, and some may be wrong.
Found by Aaron M. Ucko in the GNU Hurd via Bdale Garbee,
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=829624
- We use the input line number at several places to distinguish
same-line from different-line input. That plainly doesn't work
with user-defined macros, leading to random breakage.
- Is it possible to further simplify ENDBODY_SPACE?
- Find better ways to prevent endless loops
@ -629,8 +533,6 @@ are mere guesses, and some may be wrong.
output through libz.
- Privilege separation (see OpenSSH).
- Enable caching support via HTTP 304 and If-Modified-Since.
- Have Mac OSX systems automatically disable -static compilation of the
CGI: -static isn't supported.
************************************************************************
* to improve in the groff_mdoc(7) macros

View File

@ -1,7 +1,7 @@
.\" $Id: apropos.1,v 1.47 2018/02/23 18:54:02 schwarze Exp $
.\" $Id: apropos.1,v 1.49 2018/11/22 12:33:52 schwarze Exp $
.\"
.\" Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
.\" Copyright (c) 2011, 2012, 2014, 2017 Ingo Schwarze <schwarze@openbsd.org>
.\" Copyright (c) 2011,2012,2014,2017,2018 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
@ -15,7 +15,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: February 23 2018 $
.Dd $Mdocdate: November 22 2018 $
.Dt APROPOS 1
.Os
.Sh NAME
@ -51,8 +51,7 @@ searches for
.Xr makewhatis 8
databases in the default paths stipulated by
.Xr man 1
and uses case-insensitive substring matching
.Pq the Cm = No operator
and uses case-insensitive extended regular expression matching
over manual names and descriptions
.Pq the Li \&Nm No and Li \&Nd No macro keys .
Multiple terms imply pairwise
@ -93,7 +92,7 @@ format.
Search for all words in
.Ar expression
in manual page names only.
The search is case insensitive and matches whole words only.
The search is case-insensitive and matches whole words only.
In this mode, macro keys, comparison operators, and logical operators
are not available.
.It Fl k
@ -123,7 +122,7 @@ Restrict the search to pages for the specified
.Xr machine 1
architecture.
.Ar arch
is case insensitive.
is case-insensitive.
By default, pages for all architectures are shown.
.It Fl s Ar section
Restrict the search to the specified section of the manual.
@ -199,7 +198,7 @@ Operator
.Cm =
evaluates a substring, while
.Cm \(ti
evaluates a regular expression.
evaluates a case-sensitive extended regular expression.
.It Fl i Ar term
If
.Ar term
@ -208,26 +207,10 @@ is evaluated case-insensitively.
Has no effect on substring terms.
.El
.Pp
Results are sorted according to the following criteria:
.Bl -enum
.It
The manpath directory tree the page is found in, according to the
order specified with
.Fl M ,
.Fl m ,
the
.Ev MANPATH
environment variable, the
.Xr man.conf 5
configuration file, or the default documented in
.Xr man.conf 5 .
.It
The section number in ascending numerical order.
.It
The page name in ascending
Results are sorted first according to the section number in ascending
numerical order, then by the page name in ascending
.Xr ascii 7
alphabetical order, case-insensitive.
.El
.Pp
Each output line is formatted as
.Pp
@ -339,7 +322,7 @@ function arguments appearing on
.Ic \&Fn
lines
.It Li \&Fn
fuction names marked up with
function names marked up with
.Ic \&Fo
macros
.It Li \&In
@ -407,7 +390,7 @@ Search for
.Qq .cf
as a substring of manual names and descriptions:
.Pp
.Dl $ apropos .cf
.Dl $ apropos =.cf
.Pp
Include matches for
.Qq .cnf
@ -415,9 +398,9 @@ and
.Qq .conf
as well:
.Pp
.Dl $ apropos .cf .cnf .conf
.Dl $ apropos =.cf =.cnf =.conf
.Pp
Search in names and descriptions using a regular expression:
Search in names and descriptions using a case-sensitive regular expression:
.Pp
.Dl $ apropos \(aq\(tiset.?[ug]id\(aq
.Pp
@ -448,6 +431,24 @@ The following two invocations are equivalent:
.Xr man 1 ,
.Xr re_format 7 ,
.Xr makewhatis 8
.Sh STANDARDS
The
.Nm
utility is compliant with the
.St -p1003.1-2008
specification of
.Xr man 1
.Fl k .
.Pp
All options, the
.Nm whatis
command, support for logical operators, macro keys,
substring matching, sorting of results, the environment variables
.Ev MANPAGER
and
.Ev MANPATH ,
the database format, and the configuration file
are extensions to that specification.
.Sh HISTORY
Part of the functionality of
.Nm whatis

54
contrib/mandoc/arch.c Normal file
View File

@ -0,0 +1,54 @@
/* $Id: arch.c,v 1.14 2019/03/04 13:01:57 schwarze Exp $ */
/*
* Copyright (c) 2017, 2019 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "config.h"
#include <string.h>
#include "roff.h"
int
arch_valid(const char *arch, enum mandoc_os os)
{
const char *openbsd_arch[] = {
"alpha", "amd64", "arm64", "armv7", "hppa", "i386",
"landisk", "loongson", "luna88k", "macppc", "mips64",
"octeon", "sgi", "socppc", "sparc64", NULL
};
const char *netbsd_arch[] = {
"acorn26", "acorn32", "algor", "alpha", "amiga",
"arc", "atari",
"bebox", "cats", "cesfic", "cobalt", "dreamcast",
"emips", "evbarm", "evbmips", "evbppc", "evbsh3", "evbsh5",
"hp300", "hpcarm", "hpcmips", "hpcsh", "hppa",
"i386", "ibmnws", "luna68k",
"mac68k", "macppc", "mipsco", "mmeye", "mvme68k", "mvmeppc",
"netwinder", "news68k", "newsmips", "next68k",
"pc532", "playstation2", "pmax", "pmppc", "prep",
"sandpoint", "sbmips", "sgimips", "shark",
"sparc", "sparc64", "sun2", "sun3",
"vax", "walnut", "x68k", "x86", "x86_64", "xen", NULL
};
const char **arches[] = { NULL, netbsd_arch, openbsd_arch };
const char **arch_p;
if ((arch_p = arches[os]) == NULL)
return 1;
for (; *arch_p != NULL; arch_p++)
if (strcmp(*arch_p, arch) == 0)
return 1;
return 0;
}

View File

@ -1,4 +1,4 @@
/* $Id: att.c,v 1.16 2017/06/24 14:38:32 schwarze Exp $ */
/* $Id: att.c,v 1.18 2018/12/13 11:55:46 schwarze Exp $ */
/*
* Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
*
@ -19,9 +19,7 @@
#include <sys/types.h>
#include <string.h>
#include "mandoc.h"
#include "roff.h"
#include "mdoc.h"
#include "libmdoc.h"
#define LINE(x, y) \

View File

@ -1,7 +1,7 @@
/* $Id: cgi.c,v 1.158 2018/05/29 20:32:45 schwarze Exp $ */
/* $Id: cgi.c,v 1.166 2019/03/06 12:32:41 schwarze Exp $ */
/*
* Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014, 2015, 2016, 2017 Ingo Schwarze <schwarze@usta.de>
* Copyright (c) 2014, 2015, 2016, 2017, 2018 Ingo Schwarze <schwarze@usta.de>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -38,6 +38,7 @@
#include "roff.h"
#include "mdoc.h"
#include "man.h"
#include "mandoc_parse.h"
#include "main.h"
#include "manconf.h"
#include "mansearch.h"
@ -69,6 +70,7 @@ enum focus {
static void html_print(const char *);
static void html_putchar(char);
static int http_decode(char *);
static void http_encode(const char *p);
static void parse_manpath_conf(struct req *);
static void parse_path_info(struct req *req, const char *path);
static void parse_query_string(struct req *, const char *);
@ -90,6 +92,7 @@ static void resp_format(const struct req *, const char *);
static void resp_searchform(const struct req *, enum focus);
static void resp_show(const struct req *, const char *);
static void set_query_attr(char **, char **);
static int validate_arch(const char *);
static int validate_filename(const char *);
static int validate_manpath(const struct req *, const char *);
static int validate_urifrag(const char *);
@ -315,6 +318,18 @@ http_decode(char *p)
return 1;
}
static void
http_encode(const char *p)
{
for (; *p != '\0'; p++) {
if (isalnum((unsigned char)*p) == 0 &&
strchr("-._~", *p) == NULL)
printf("%%%2.2X", (unsigned char)*p);
else
putchar(*p);
}
}
static void
resp_begin_http(int code, const char *msg)
{
@ -489,6 +504,18 @@ validate_manpath(const struct req *req, const char* manpath)
return 0;
}
static int
validate_arch(const char *arch)
{
int i;
for (i = 0; i < arch_MAX; i++)
if (strcmp(arch, arch_names[i]) == 0)
return 1;
return 0;
}
static int
validate_filename(const char *file)
{
@ -562,9 +589,11 @@ pg_redirect(const struct req *req, const char *name)
printf("%s/", req->q.manpath);
if (req->q.arch != NULL)
printf("%s/", req->q.arch);
printf("%s", name);
if (req->q.sec != NULL)
printf(".%s", req->q.sec);
http_encode(name);
if (req->q.sec != NULL) {
putchar('.');
http_encode(req->q.sec);
}
printf("\r\nContent-Type: text/html; charset=utf-8\r\n\r\n");
}
@ -820,7 +849,7 @@ resp_format(const struct req *req, const char *file)
{
struct manoutput conf;
struct mparse *mp;
struct roff_man *man;
struct roff_meta *meta;
void *vp;
int fd;
int usepath;
@ -831,37 +860,26 @@ resp_format(const struct req *req, const char *file)
}
mchars_alloc();
mp = mparse_alloc(MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1,
MANDOCERR_MAX, NULL, MANDOC_OS_OTHER, req->q.manpath);
mp = mparse_alloc(MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1 |
MPARSE_VALIDATE, MANDOC_OS_OTHER, req->q.manpath);
mparse_readfd(mp, fd, file);
close(fd);
meta = mparse_result(mp);
memset(&conf, 0, sizeof(conf));
conf.fragment = 1;
conf.style = mandoc_strdup(CSS_DIR "/mandoc.css");
conf.toc = 1;
usepath = strcmp(req->q.manpath, req->p[0]);
mandoc_asprintf(&conf.man, "/%s%s%s%s%%N.%%S",
scriptname, *scriptname == '\0' ? "" : "/",
usepath ? req->q.manpath : "", usepath ? "/" : "");
mparse_result(mp, &man, NULL);
if (man == NULL) {
warnx("fatal mandoc error: %s/%s", req->q.manpath, file);
pg_error_internal();
mparse_free(mp);
mchars_free();
return;
}
vp = html_alloc(&conf);
if (man->macroset == MACROSET_MDOC) {
mdoc_validate(man);
html_mdoc(vp, man);
} else {
man_validate(man);
html_man(vp, man);
}
if (meta->macroset == MACROSET_MDOC)
html_mdoc(vp, meta);
else
html_man(vp, meta);
html_free(vp);
mparse_free(mp);
@ -1089,7 +1107,7 @@ main(void)
return EXIT_FAILURE;
}
if ( ! (NULL == req.q.arch || validate_urifrag(req.q.arch))) {
if (req.q.arch != NULL && validate_arch(req.q.arch) == 0) {
pg_error_badrequest(
"You specified an invalid architecture.");
return EXIT_FAILURE;
@ -1115,80 +1133,74 @@ main(void)
}
/*
* If PATH_INFO is not a file name, translate it to a query.
* Translate PATH_INFO to a query.
*/
static void
parse_path_info(struct req *req, const char *path)
{
char *dir[4];
int i;
const char *name, *sec, *end;
req->isquery = 0;
req->q.equal = 1;
req->q.manpath = mandoc_strdup(path);
req->q.manpath = NULL;
req->q.arch = NULL;
/* Mandatory manual page name. */
if ((req->q.query = strrchr(req->q.manpath, '/')) == NULL) {
req->q.query = req->q.manpath;
req->q.manpath = NULL;
} else
*req->q.query++ = '\0';
if ((name = strrchr(path, '/')) == NULL)
name = path;
else
name++;
/* Optional trailing section. */
if ((req->q.sec = strrchr(req->q.query, '.')) != NULL) {
if(isdigit((unsigned char)req->q.sec[1])) {
*req->q.sec++ = '\0';
req->q.sec = mandoc_strdup(req->q.sec);
} else
req->q.sec = NULL;
sec = strrchr(name, '.');
if (sec != NULL && isdigit((unsigned char)*++sec)) {
req->q.query = mandoc_strndup(name, sec - name - 1);
req->q.sec = mandoc_strdup(sec);
} else {
req->q.query = mandoc_strdup(name);
req->q.sec = NULL;
}
/* Handle the case of name[.section] only. */
if (req->q.manpath == NULL)
if (name == path)
return;
req->q.query = mandoc_strdup(req->q.query);
/* Split directory components. */
dir[i = 0] = req->q.manpath;
while ((dir[i + 1] = strchr(dir[i], '/')) != NULL) {
if (++i == 3) {
pg_error_badrequest(
"You specified too many directory components.");
exit(EXIT_FAILURE);
}
*dir[i]++ = '\0';
}
/* Optional manpath. */
if ((i = validate_manpath(req, req->q.manpath)) == 0)
end = strchr(path, '/');
req->q.manpath = mandoc_strndup(path, end - path);
if (validate_manpath(req, req->q.manpath)) {
path = end + 1;
if (name == path)
return;
} else {
free(req->q.manpath);
req->q.manpath = NULL;
else if (dir[1] == NULL)
return;
}
/* Optional section. */
if (strncmp(dir[i], "man", 3) == 0) {
if (strncmp(path, "man", 3) == 0 || strncmp(path, "cat", 3) == 0) {
path += 3;
end = strchr(path, '/');
free(req->q.sec);
req->q.sec = mandoc_strdup(dir[i++] + 3);
req->q.sec = mandoc_strndup(path, end - path);
path = end + 1;
if (name == path)
return;
}
if (dir[i] == NULL) {
if (req->q.manpath == NULL)
free(dir[0]);
return;
/* Optional architecture. */
end = strchr(path, '/');
if (end + 1 != name) {
pg_error_badrequest(
"You specified too many directory components.");
exit(EXIT_FAILURE);
}
if (dir[i + 1] != NULL) {
req->q.arch = mandoc_strndup(path, end - path);
if (validate_arch(req->q.arch) == 0) {
pg_error_badrequest(
"You specified an invalid directory component.");
exit(EXIT_FAILURE);
}
/* Optional architecture. */
if (i) {
req->q.arch = mandoc_strdup(dir[i]);
if (req->q.manpath == NULL)
free(dir[0]);
} else
req->q.arch = dir[0];
}
/*

View File

@ -1,7 +1,7 @@
/* $Id: chars.c,v 1.73 2017/08/23 13:01:29 schwarze Exp $ */
/* $Id: chars.c,v 1.78 2018/12/15 19:30:26 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2011,2014,2015,2017,2018 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
@ -23,6 +23,7 @@
#include <ctype.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -47,20 +48,13 @@ static struct ln lines[] = {
{ " ", ascii_nbrsp, 0x00a0 },
{ "~", ascii_nbrsp, 0x00a0 },
{ "0", " ", 0x2002 },
{ "|", "", 0 },
{ "^", "", 0 },
{ "&", "", 0 },
{ "%", "", 0 },
{ ":", ascii_break, 0 },
/* XXX The following three do not really belong here. */
{ "t", "", 0 },
{ "c", "", 0 },
{ "}", "", 0 },
/* Lines. */
{ "ba", "|", 0x007c },
{ "br", "|", 0x2502 },
{ "ul", "_", 0x005f },
{ "_", "_", 0x005f },
{ "ru", "_", 0x005f },
{ "rn", "-", 0x203e },
{ "bb", "|", 0x00a6 },
@ -82,10 +76,10 @@ static struct ln lines[] = {
{ "sh", "#", 0x0023 },
{ "CR", "<cr>", 0x21b5 },
{ "OK", "\\/", 0x2713 },
{ "CL", "<club>", 0x2663 },
{ "SP", "<spade>", 0x2660 },
{ "HE", "<heart>", 0x2665 },
{ "DI", "<diamond>", 0x2666 },
{ "CL", "C", 0x2663 },
{ "SP", "S", 0x2660 },
{ "HE", "H", 0x2665 },
{ "DI", "D", 0x2666 },
/* Legal symbols. */
{ "co", "(C)", 0x00a9 },
@ -240,7 +234,7 @@ static struct ln lines[] = {
{ "Ah", "<Aleph>", 0x2135 },
{ "Im", "<Im>", 0x2111 },
{ "Re", "<Re>", 0x211c },
{ "wp", "P", 0x2118 },
{ "wp", "p", 0x2118 },
{ "pd", "<del>", 0x2202 },
{ "-h", "/h", 0x210f },
{ "hbar", "/h", 0x210f },
@ -287,6 +281,7 @@ static struct ln lines[] = {
{ "ho", ",", 0x02db },
{ "ha", "^", 0x005e },
{ "ti", "~", 0x007e },
{ "u02DC", "~", 0x02dc },
/* Accented letters. */
{ "'A", "'\bA", 0x00c1 },
@ -294,11 +289,13 @@ static struct ln lines[] = {
{ "'I", "'\bI", 0x00cd },
{ "'O", "'\bO", 0x00d3 },
{ "'U", "'\bU", 0x00da },
{ "'Y", "'\bY", 0x00dd },
{ "'a", "'\ba", 0x00e1 },
{ "'e", "'\be", 0x00e9 },
{ "'i", "'\bi", 0x00ed },
{ "'o", "'\bo", 0x00f3 },
{ "'u", "'\bu", 0x00fa },
{ "'y", "'\by", 0x00fd },
{ "`A", "`\bA", 0x00c0 },
{ "`E", "`\bE", 0x00c8 },
{ "`I", "`\bI", 0x00cc },
@ -359,7 +356,7 @@ static struct ln lines[] = {
{ "Eu", "EUR", 0x20ac },
{ "eu", "EUR", 0x20ac },
{ "Ye", "=\bY", 0x00a5 },
{ "Po", "GBP", 0x00a3 },
{ "Po", "-\bL", 0x00a3 },
{ "Cs", "o\bx", 0x00a4 },
{ "Fn", ",\bf", 0x0192 },
@ -460,7 +457,7 @@ mchars_spec2cp(const char *p, size_t sz)
end = p + sz;
ln = ohash_find(&mchars, ohash_qlookupi(&mchars, p, &end));
return ln != NULL ? ln->unicode : sz == 1 ? (unsigned char)*p : -1;
return ln != NULL ? ln->unicode : -1;
}
int
@ -490,10 +487,8 @@ mchars_spec2str(const char *p, size_t sz, size_t *rsz)
end = p + sz;
ln = ohash_find(&mchars, ohash_qlookupi(&mchars, p, &end));
if (ln == NULL) {
*rsz = 1;
return sz == 1 ? p : NULL;
}
if (ln == NULL)
return NULL;
*rsz = strlen(ln->ascii);
return ln->ascii;

View File

@ -6,15 +6,12 @@
#define __attribute__(x)
#endif
#if defined(__linux__) || defined(__MINT__)
#define _GNU_SOURCE /* See test-*.c what needs this. */
#endif
#include <sys/types.h>
#define MAN_CONF_FILE "/etc/man.conf"
#define MANPATH_BASE "/usr/share/man"
#define MANPATH_DEFAULT "/usr/share/man:/usr/local/man"
#define OSENUM MANDOC_OS_OTHER
#define UTF8_LOCALE "en_US.UTF-8"
#define HAVE_CMSG_XPG42 0
#define HAVE_DIRENT_NAMLEN 1
@ -25,6 +22,7 @@
#define HAVE_GETLINE 1
#define HAVE_GETSUBOPT 1
#define HAVE_ISBLANK 1
#define HAVE_LESS_T 1
#define HAVE_MKDTEMP 1
#define HAVE_NTOHL 1
#define HAVE_PLEDGE 0

View File

@ -1,8 +1,8 @@
#!/bin/sh
#
# $Id: configure,v 1.66 2018/07/31 15:34:00 schwarze Exp $
# $Id: configure,v 1.70 2019/03/06 16:04:31 schwarze Exp $
#
# Copyright (c) 2014,2015,2016,2017,2018 Ingo Schwarze <schwarze@openbsd.org>
# Copyright (c) 2014-2019 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
@ -37,6 +37,7 @@ SOURCEDIR=`dirname "$0"`
MANPATH_BASE="/usr/share/man:/usr/X11R6/man"
MANPATH_DEFAULT="/usr/share/man:/usr/X11R6/man:/usr/local/man"
OSENUM=
OSNAME=
UTF8_LOCALE=
@ -64,6 +65,7 @@ HAVE_FTS_COMPARE_CONST=
HAVE_GETLINE=
HAVE_GETSUBOPT=
HAVE_ISBLANK=
HAVE_LESS_T=
HAVE_MKDTEMP=
HAVE_NANOSLEEP=
HAVE_NTOHL=
@ -90,6 +92,9 @@ HAVE_SYS_ENDIAN=
HAVE_VASPRINTF=
HAVE_WCHAR=
NEED_GNU_SOURCE=0
NEED_OPENBSD_SOURCE=0
PREFIX="/usr/local"
BINDIR=
SBINDIR=
@ -154,31 +159,34 @@ ismanual() {
# In case of failure, do not decide anything yet.
# Arguments: test file name, test var name, additional CFLAGS
singletest() {
n=${1}${3}${4}
cat 1>&3 << __HEREDOC__
testing ${1}${3} ...
${COMP} -o test-${1} test-${1}.c ${3}
testing ${n} ...
${COMP} -o test-${1} test-${1}.c ${3} ${4}
__HEREDOC__
if ${COMP} -o "test-${1}" "${SOURCEDIR}/test-${1}.c" ${3} 1>&3 2>&3
if ${COMP} -o "test-${1}" "${SOURCEDIR}/test-${1}.c" ${3} ${4} 1>&3 2>&3
then
echo "partial result of ${1}${3}: ${CC} succeeded" 1>&3
echo "partial result of ${n}: ${CC} succeeded" 1>&3
else
echo "result of ${1}${3}: ${CC} failed with exit status $?" 1>&3
echo "result of compiling ${1}${3}: no" 1>&3
echo "result of ${n}: ${CC} failed with exit status $?" 1>&3
echo "result of compiling ${n}: no" 1>&3
echo 1>&3
return 1
fi
if ./test-${1} 1>&3 2>&3; then
echo "tested ${1}${3}: yes" 1>&2
echo "result of running ${1}${3}: yes" 1>&3
echo "tested ${n}: yes" 1>&2
echo "result of running ${n}: yes" 1>&3
echo 1>&3
eval HAVE_${2}=1
[ "X$3" = "X-D_GNU_SOURCE" ] && NEED_GNU_SOURCE=1
[ "X$3" = "X-D_OPENBSD_SOURCE" ] && NEED_OPENBSD_SOURCE=1
rm "test-${1}"
return 0
else
echo "result of ${1}${3}: execution failed with exit status $?" 1>&3
echo "result of running ${1}${3}: no" 1>&3
echo "result of ${n}: execution failed with exit status $?" 1>&3
echo "result of running ${n}: no" 1>&3
echo 1>&3
rm "test-${1}"
return 1
@ -191,8 +199,8 @@ __HEREDOC__
runtest() {
eval _manual=\${HAVE_${2}}
ismanual "${1}" "${2}" "${_manual}" && return 0
singletest "${1}" "${2}" "${3}" && return 0
echo "tested ${1}${3}: no" 1>&2
singletest "${1}" "${2}" "${3}" "${4}" && return 0
echo "tested ${1}${3}${4}: no" 1>&2
eval HAVE_${2}=0
return 1
}
@ -213,28 +221,52 @@ get_locale() {
return 0;
}
# --- operating system -------------------------------------------------
if [ -n "${OSENUM}" ]; then
echo "OSENUM specified manually: ${OSENUM}" 1>&2
echo "OSENUM specified manually: ${OSENUM}" 1>&3
else
OSDETECT=`uname`
if [ "X${OSDETECT}" = "XNetBSD" ]; then
OSENUM=MANDOC_OS_NETBSD
elif [ "X${OSDETECT}" = "XOpenBSD" ]; then
OSENUM=MANDOC_OS_OPENBSD
else
OSENUM=MANDOC_OS_OTHER
fi
echo "tested operating system: ${OSDETECT} -> OSENUM=${OSENUM}" 1>&2
echo "tested operating system: ${OSDETECT} -> OSENUM=${OSENUM}" 1>&3
unset OSDETECT
fi
echo 1>&3
# --- compiler options -------------------------------------------------
DEFCFLAGS="-g -W -Wall -Wmissing-prototypes -Wstrict-prototypes -Wwrite-strings -Wno-unused-parameter"
if [ -n "${CFLAGS}" ]; then
COMP="${CC} ${CFLAGS}"
echo "selected CFLAGS=\"${CFLAGS}\" (manual)" 1>&2
echo "selected CFLAGS=\"${CFLAGS}\" (manual)" 1>&3
echo 1>&3
else
CFLAGS="-g -W -Wall -Wmissing-prototypes -Wstrict-prototypes"
CFLAGS="${CFLAGS} -Wwrite-strings -Wno-unused-parameter"
COMP="${CC} ${CFLAGS} -Wno-unused -Werror"
echo -n "tested ${CC} -W: " 1>&2
echo -n "testing ${CC} -W: " 1>&3
runtest noop WFLAG || true
if [ "${HAVE_WFLAG}" -eq 0 ]; then
CFLAGS="-g"
COMP="${CC} ${CFLAGS}"
fi
echo "selected CFLAGS=\"${CFLAGS}\"" 1>&2
echo "selected CFLAGS=\"${CFLAGS}\"" 1>&3
echo 1>&3
else
COMP="${CC} ${DEFCFLAGS} -Wno-unused -Werror"
fi
echo -n "tested ${CC} -W: " 1>&2
echo -n "testing ${CC} -W: " 1>&3
runtest noop WFLAG || true
if [ -n "${CFLAGS}" ]; then
echo "CFLAGS specified manually:" 1>&3
elif [ ${HAVE_WFLAG} -eq 0 ]; then
CFLAGS="-g"
else
CFLAGS="${DEFCFLAGS}"
fi
echo "selected CFLAGS=\"${CFLAGS}\"" 1>&2
echo "selected CFLAGS=\"${CFLAGS}\"" 1>&3
echo 1>&3
COMP="${CC} ${CFLAGS}"
[ ${HAVE_WFLAG} -eq 0 ] || COMP="${COMP} -Wno-unused -Werror"
if [ -n "${STATIC}" ]; then
echo "selected STATIC=\"${STATIC}\" (manual)" 1>&2
@ -257,7 +289,8 @@ runtest be32toh SYS_ENDIAN -DSYS_ENDIAN || true
runtest EFTYPE EFTYPE || true
runtest err ERR || true
runtest getline GETLINE || true
runtest getsubopt GETSUBOPT || true
singletest getsubopt GETSUBOPT || \
runtest getsubopt GETSUBOPT -D_GNU_SOURCE || true
runtest isblank ISBLANK || true
runtest mkdtemp MKDTEMP || true
runtest ntohl NTOHL || true
@ -266,19 +299,25 @@ runtest PATH_MAX PATH_MAX || true
runtest pledge PLEDGE || true
runtest sandbox_init SANDBOX_INIT || true
runtest progname PROGNAME || true
runtest reallocarray REALLOCARRAY || true
runtest recallocarray RECALLOCARRAY || true
singletest reallocarray REALLOCARRAY || \
runtest reallocarray REALLOCARRAY -D_OPENBSD_SOURCE || true
singletest recallocarray RECALLOCARRAY || \
runtest recallocarray RECALLOCARRAY -D_OPENBSD_SOURCE || true
runtest rewb-bsd REWB_BSD || true
runtest rewb-sysv REWB_SYSV || true
runtest strcasestr STRCASESTR || true
singletest strcasestr STRCASESTR || \
runtest strcasestr STRCASESTR -D_GNU_SOURCE || true
runtest stringlist STRINGLIST || true
runtest strlcat STRLCAT || true
runtest strlcpy STRLCPY || true
runtest strndup STRNDUP || true
runtest strptime STRPTIME || true
singletest strptime STRPTIME || \
runtest strptime STRPTIME -D_GNU_SOURCE || true
runtest strsep STRSEP || true
runtest strtonum STRTONUM || true
runtest vasprintf VASPRINTF || true
singletest strtonum STRTONUM || \
runtest strtonum STRTONUM -D_OPENBSD_SOURCE || true
singletest vasprintf VASPRINTF || \
runtest vasprintf VASPRINTF -D_GNU_SOURCE || true
if [ ${HAVE_ENDIAN} -eq 0 -a \
${HAVE_SYS_ENDIAN} -eq 0 -a \
@ -296,9 +335,25 @@ else
runtest fts FTS || true
fi
if ismanual "less -T" LESS_T ${HAVE_LESS_T}; then
:
elif less -ET /dev/null test-noop.c 1>/dev/null 2>&3; then
HAVE_LESS_T=1
echo "tested less -T: yes" 1>&2
echo "tested less -T: yes" 1>&3
echo 1>&3
else
HAVE_LESS_T=0
echo "tested less -T: no" 1>&2
echo "tested less -T: no" 1>&3
echo 1>&3
fi
# --- wide character and locale support ---
if get_locale; then
runtest wchar WCHAR -DUTF8_LOCALE=\"${UTF8_LOCALE}\" || true
singletest wchar WCHAR -DUTF8_LOCALE=\"${UTF8_LOCALE}\" || \
runtest wchar WCHAR -D_GNU_SOURCE \
-DUTF8_LOCALE=\"${UTF8_LOCALE}\" || true
else
HAVE_WCHAR=0
echo "tested wchar: no (no UTF8_LOCALE)" 1>&2
@ -383,12 +438,11 @@ cat << __HEREDOC__
#define __attribute__(x)
#endif
#if defined(__linux__) || defined(__MINT__)
#define _GNU_SOURCE /* See test-*.c what needs this. */
#endif
__HEREDOC__
[ ${NEED_GNU_SOURCE} -eq 0 ] || echo "#define _GNU_SOURCE"
[ ${NEED_OPENBSD_SOURCE} -eq 0 ] || echo "#define _OPENBSD_SOURCE"
[ ${HAVE_GETLINE} -eq 0 -o \
${HAVE_REALLOCARRAY} -eq 0 -o ${HAVE_RECALLOCARRAY} -eq 0 -o \
${HAVE_STRLCAT} -eq 0 -o ${HAVE_STRLCPY} -eq 0 -o \
@ -401,6 +455,7 @@ echo
echo "#define MAN_CONF_FILE \"/etc/${MANM_MANCONF}\""
echo "#define MANPATH_BASE \"${MANPATH_BASE}\""
echo "#define MANPATH_DEFAULT \"${MANPATH_DEFAULT}\""
echo "#define OSENUM ${OSENUM}"
[ -n "${OSNAME}" ] && echo "#define OSNAME \"${OSNAME}\""
[ -n "${UTF8_LOCALE}" ] && echo "#define UTF8_LOCALE \"${UTF8_LOCALE}\""
[ -n "${HOMEBREWDIR}" ] && echo "#define HOMEBREWDIR \"${HOMEBREWDIR}\""
@ -422,6 +477,7 @@ cat << __HEREDOC__
#define HAVE_GETLINE ${HAVE_GETLINE}
#define HAVE_GETSUBOPT ${HAVE_GETSUBOPT}
#define HAVE_ISBLANK ${HAVE_ISBLANK}
#define HAVE_LESS_T ${HAVE_LESS_T}
#define HAVE_MKDTEMP ${HAVE_MKDTEMP}
#define HAVE_NTOHL ${HAVE_NTOHL}
#define HAVE_PLEDGE ${HAVE_PLEDGE}

View File

@ -1,6 +1,6 @@
# $Id: configure.local.example,v 1.34 2018/07/31 15:34:00 schwarze Exp $
# $Id: configure.local.example,v 1.36 2019/03/06 10:18:58 schwarze Exp $
#
# Copyright (c) 2014,2015,2016,2017,2018 Ingo Schwarze <schwarze@openbsd.org>
# Copyright (c) 2014-2019 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
@ -67,6 +67,17 @@ MANPATH_DEFAULT="/usr/share/man:/usr/X11R6/man:/usr/local/man"
MANPATH_BASE="/usr/share/man:/usr/X11R6/man"
# When man(1) is called with the -S option and no manual page is
# found matching the requested name and the requested architecture,
# it tries to figure out whether the requested architecture is valid
# for the present operating system. Normally, ./configure detects
# the operating system using uname(1). If that fails or is not
# desired, either of the following lines can be used:
OSENUM=MANDOC_OS_NETBSD
OSENUM=MANDOC_OS_OPENBSD
OSENUM=MANDOC_OS_OTHER
# In manual pages written in the mdoc(7) language, the operating system
# version is displayed in the page footer line. If an operating system
# is specified as an argument to the .Os macro, that is always used.
@ -77,7 +88,7 @@ MANPATH_BASE="/usr/share/man:/usr/X11R6/man"
# If you do not want uname(3) to be called but instead want a fixed
# string to be used, use the following line:
OSNAME="OpenBSD 6.3"
OSNAME="OpenBSD 6.5"
# The following installation directories are used.
# It is possible to set only one or a few of these variables,
@ -293,6 +304,7 @@ HAVE_FTS_COMPARE_CONST=0 # Setting this implies HAVE_FTS=1.
HAVE_GETLINE=0
HAVE_GETSUBOPT=0
HAVE_ISBLANK=0
HAVE_LESS_T=0
HAVE_MKDTEMP=0
HAVE_NTOHL=0
HAVE_O_DIRECTORY=0

View File

@ -1,4 +1,4 @@
/* $Id: dbm.c,v 1.5 2016/10/18 22:27:25 schwarze Exp $ */
/* $Id: dbm.c,v 1.6 2018/11/19 19:22:07 schwarze Exp $ */
/*
* Copyright (c) 2016 Ingo Schwarze <schwarze@openbsd.org>
*
@ -151,17 +151,17 @@ dbm_page_get(int32_t ip)
assert(ip < npages);
res.name = dbm_get(pages[ip].name);
if (res.name == NULL)
res.name = "(NULL)";
res.name = "(NULL)\0";
res.sect = dbm_get(pages[ip].sect);
if (res.sect == NULL)
res.sect = "(NULL)";
res.sect = "(NULL)\0";
res.arch = pages[ip].arch ? dbm_get(pages[ip].arch) : NULL;
res.desc = dbm_get(pages[ip].desc);
if (res.desc == NULL)
res.desc = "(NULL)";
res.file = dbm_get(pages[ip].file);
if (res.file == NULL)
res.file = " (NULL)";
res.file = " (NULL)\0";
res.addr = dbm_addr(pages + ip);
return &res;
}

View File

@ -1,4 +1,4 @@
/* $Id: demandoc.c,v 1.29 2017/06/24 14:38:32 schwarze Exp $ */
/* $Id: demandoc.c,v 1.33 2019/03/03 11:01:15 schwarze Exp $ */
/*
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
*
@ -29,6 +29,7 @@
#include "roff.h"
#include "man.h"
#include "mdoc.h"
#include "mandoc_parse.h"
static void pline(int, int *, int *, int);
static void pman(const struct roff_node *, int *, int *, int);
@ -78,8 +79,8 @@ main(int argc, char *argv[])
argv += optind;
mchars_alloc();
mp = mparse_alloc(MPARSE_SO, MANDOCERR_MAX, NULL,
MANDOC_OS_OTHER, NULL);
mp = mparse_alloc(MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1 |
MPARSE_VALIDATE, MANDOC_OS_OTHER, NULL);
assert(mp);
if (argc < 1)
@ -109,24 +110,19 @@ usage(void)
static void
pmandoc(struct mparse *mp, int fd, const char *fn, int list)
{
struct roff_man *man;
struct roff_meta *meta;
int line, col;
mparse_readfd(mp, fd, fn);
close(fd);
mparse_result(mp, &man, NULL);
meta = mparse_result(mp);
line = 1;
col = 0;
if (man == NULL)
return;
if (man->macroset == MACROSET_MDOC) {
mdoc_validate(man);
pmdoc(man->first->child, &line, &col, list);
} else {
man_validate(man);
pman(man->first->child, &line, &col, list);
}
if (meta->macroset == MACROSET_MDOC)
pmdoc(meta->first->child, &line, &col, list);
else
pman(meta->first->child, &line, &col, list);
if ( ! list)
putchar('\n');

View File

@ -1,7 +1,7 @@
/* $Id: eqn.c,v 1.78 2017/07/15 16:26:17 schwarze Exp $ */
/* $Id: eqn.c,v 1.83 2018/12/14 06:33:14 schwarze Exp $ */
/*
* Copyright (c) 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2014, 2015, 2017, 2018 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
@ -30,8 +30,9 @@
#include "mandoc_aux.h"
#include "mandoc.h"
#include "roff.h"
#include "eqn.h"
#include "libmandoc.h"
#include "libroff.h"
#include "eqn_parse.h"
#define EQN_NEST_MAX 128 /* maximum nesting of defines */
#define STRNEQ(p1, sz1, p2, sz2) \
@ -284,6 +285,13 @@ enum parse_mode {
MODE_TOK
};
struct eqn_def {
char *key;
size_t keysz;
char *val;
size_t valsz;
};
static struct eqn_box *eqn_box_alloc(struct eqn_node *, struct eqn_box *);
static struct eqn_box *eqn_box_makebinary(struct eqn_node *,
struct eqn_box *);
@ -295,12 +303,11 @@ static void eqn_undef(struct eqn_node *);
struct eqn_node *
eqn_alloc(struct mparse *parse)
eqn_alloc(void)
{
struct eqn_node *ep;
ep = mandoc_calloc(1, sizeof(*ep));
ep->parse = parse;
ep->gsize = EQN_DEFSIZE;
return ep;
}
@ -399,7 +406,7 @@ eqn_next(struct eqn_node *ep, enum parse_mode mode)
ep->end = strchr(ep->start + 1, *ep->start);
ep->start++; /* Skip opening quote. */
if (ep->end == NULL) {
mandoc_msg(MANDOCERR_ARG_QUOTE, ep->parse,
mandoc_msg(MANDOCERR_ARG_QUOTE,
ep->node->line, ep->node->pos, NULL);
ep->end = strchr(ep->start, '\0');
}
@ -420,7 +427,7 @@ eqn_next(struct eqn_node *ep, enum parse_mode mode)
if ((def = eqn_def_find(ep)) == NULL)
break;
if (++lim > EQN_NEST_MAX) {
mandoc_msg(MANDOCERR_ROFFLOOP, ep->parse,
mandoc_msg(MANDOCERR_ROFFLOOP,
ep->node->line, ep->node->pos, NULL);
return EQN_TOK_EOF;
}
@ -468,6 +475,8 @@ eqn_next(struct eqn_node *ep, enum parse_mode mode)
void
eqn_box_free(struct eqn_box *bp)
{
if (bp == NULL)
return;
if (bp->first)
eqn_box_free(bp->first);
@ -482,6 +491,16 @@ eqn_box_free(struct eqn_box *bp)
free(bp);
}
struct eqn_box *
eqn_box_new(void)
{
struct eqn_box *bp;
bp = mandoc_calloc(1, sizeof(*bp));
bp->expectargs = UINT_MAX;
return bp;
}
/*
* Allocate a box as the last child of the parent node.
*/
@ -490,10 +509,9 @@ eqn_box_alloc(struct eqn_node *ep, struct eqn_box *parent)
{
struct eqn_box *bp;
bp = mandoc_calloc(1, sizeof(struct eqn_box));
bp = eqn_box_new();
bp->parent = parent;
bp->parent->args++;
bp->expectargs = UINT_MAX;
bp->font = bp->parent->font;
bp->size = ep->gsize;
@ -542,7 +560,7 @@ static void
eqn_delim(struct eqn_node *ep)
{
if (ep->end[0] == '\0' || ep->end[1] == '\0') {
mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
mandoc_msg(MANDOCERR_REQ_EMPTY,
ep->node->line, ep->node->pos, "delim");
if (ep->end[0] != '\0')
ep->end++;
@ -569,7 +587,7 @@ eqn_undef(struct eqn_node *ep)
struct eqn_def *def;
if (eqn_next(ep, MODE_NOSUB) == EQN_TOK_EOF) {
mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
mandoc_msg(MANDOCERR_REQ_EMPTY,
ep->node->line, ep->node->pos, "undef");
return;
}
@ -588,7 +606,7 @@ eqn_def(struct eqn_node *ep)
int i;
if (eqn_next(ep, MODE_NOSUB) == EQN_TOK_EOF) {
mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
mandoc_msg(MANDOCERR_REQ_EMPTY,
ep->node->line, ep->node->pos, "define");
return;
}
@ -617,7 +635,7 @@ eqn_def(struct eqn_node *ep)
}
if (eqn_next(ep, MODE_QUOTED) == EQN_TOK_EOF) {
mandoc_vmsg(MANDOCERR_REQ_EMPTY, ep->parse,
mandoc_msg(MANDOCERR_REQ_EMPTY,
ep->node->line, ep->node->pos, "define %s", def->key);
free(def->key);
free(def->val);
@ -666,7 +684,7 @@ eqn_parse(struct eqn_node *ep)
case EQN_TOK_TDEFINE:
if (eqn_next(ep, MODE_NOSUB) == EQN_TOK_EOF ||
eqn_next(ep, MODE_QUOTED) == EQN_TOK_EOF)
mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
mandoc_msg(MANDOCERR_REQ_EMPTY,
ep->node->line, ep->node->pos, "tdefine");
break;
case EQN_TOK_DELIM:
@ -674,8 +692,8 @@ eqn_parse(struct eqn_node *ep)
break;
case EQN_TOK_GFONT:
if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF)
mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
ep->node->line, ep->node->pos, eqn_toks[tok]);
mandoc_msg(MANDOCERR_REQ_EMPTY, ep->node->line,
ep->node->pos, "%s", eqn_toks[tok]);
break;
case EQN_TOK_MARK:
case EQN_TOK_LINEUP:
@ -690,8 +708,8 @@ eqn_parse(struct eqn_node *ep)
case EQN_TOK_DOT:
case EQN_TOK_DOTDOT:
if (parent->last == NULL) {
mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,
ep->node->line, ep->node->pos, eqn_toks[tok]);
mandoc_msg(MANDOCERR_EQN_NOBOX, ep->node->line,
ep->node->pos, "%s", eqn_toks[tok]);
cur = eqn_box_alloc(ep, parent);
cur->type = EQN_TEXT;
cur->text = mandoc_strdup("");
@ -735,8 +753,8 @@ eqn_parse(struct eqn_node *ep)
case EQN_TOK_DOWN:
case EQN_TOK_UP:
if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF)
mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
ep->node->line, ep->node->pos, eqn_toks[tok]);
mandoc_msg(MANDOCERR_REQ_EMPTY, ep->node->line,
ep->node->pos, "%s", eqn_toks[tok]);
break;
case EQN_TOK_FAT:
case EQN_TOK_ROMAN:
@ -773,14 +791,14 @@ eqn_parse(struct eqn_node *ep)
case EQN_TOK_GSIZE:
/* Accept two values: integral size and a single. */
if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF) {
mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
ep->node->line, ep->node->pos, eqn_toks[tok]);
mandoc_msg(MANDOCERR_REQ_EMPTY, ep->node->line,
ep->node->pos, "%s", eqn_toks[tok]);
break;
}
size = mandoc_strntoi(ep->start, ep->toksz, 10);
if (-1 == size) {
mandoc_msg(MANDOCERR_IT_NONUM, ep->parse,
ep->node->line, ep->node->pos, eqn_toks[tok]);
mandoc_msg(MANDOCERR_IT_NONUM, ep->node->line,
ep->node->pos, "%s", eqn_toks[tok]);
break;
}
if (EQN_TOK_GSIZE == tok) {
@ -804,8 +822,8 @@ eqn_parse(struct eqn_node *ep)
* and keep on reading.
*/
if (parent->last == NULL) {
mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,
ep->node->line, ep->node->pos, eqn_toks[tok]);
mandoc_msg(MANDOCERR_EQN_NOBOX, ep->node->line,
ep->node->pos, "%s", eqn_toks[tok]);
cur = eqn_box_alloc(ep, parent);
cur->type = EQN_TEXT;
cur->text = mandoc_strdup("");
@ -871,8 +889,8 @@ eqn_parse(struct eqn_node *ep)
* rebalance and continue reading.
*/
if (parent->last == NULL) {
mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,
ep->node->line, ep->node->pos, eqn_toks[tok]);
mandoc_msg(MANDOCERR_EQN_NOBOX, ep->node->line,
ep->node->pos, "%s", eqn_toks[tok]);
cur = eqn_box_alloc(ep, parent);
cur->type = EQN_TEXT;
cur->text = mandoc_strdup("");
@ -898,16 +916,16 @@ eqn_parse(struct eqn_node *ep)
cur->left != NULL))
break;
if (cur == NULL) {
mandoc_msg(MANDOCERR_BLK_NOTOPEN, ep->parse,
ep->node->line, ep->node->pos, eqn_toks[tok]);
mandoc_msg(MANDOCERR_BLK_NOTOPEN, ep->node->line,
ep->node->pos, "%s", eqn_toks[tok]);
break;
}
parent = cur;
if (EQN_TOK_RIGHT == tok) {
if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF) {
mandoc_msg(MANDOCERR_REQ_EMPTY,
ep->parse, ep->node->line,
ep->node->pos, eqn_toks[tok]);
ep->node->line, ep->node->pos,
"%s", eqn_toks[tok]);
break;
}
/* Handling depends on right/left. */
@ -941,8 +959,8 @@ eqn_parse(struct eqn_node *ep)
parent = parent->parent;
if (EQN_TOK_LEFT == tok &&
eqn_next(ep, MODE_SUB) == EQN_TOK_EOF) {
mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
ep->node->line, ep->node->pos, eqn_toks[tok]);
mandoc_msg(MANDOCERR_REQ_EMPTY, ep->node->line,
ep->node->pos, "%s", eqn_toks[tok]);
break;
}
parent = eqn_box_alloc(ep, parent);
@ -975,8 +993,8 @@ eqn_parse(struct eqn_node *ep)
if (cur->type == EQN_PILE)
break;
if (cur == NULL) {
mandoc_msg(MANDOCERR_IT_STRAY, ep->parse,
ep->node->line, ep->node->pos, eqn_toks[tok]);
mandoc_msg(MANDOCERR_IT_STRAY, ep->node->line,
ep->node->pos, "%s", eqn_toks[tok]);
break;
}
parent = eqn_box_alloc(ep, cur);
@ -1092,6 +1110,9 @@ eqn_free(struct eqn_node *p)
{
int i;
if (p == NULL)
return;
for (i = 0; i < (int)p->defsz; i++) {
free(p->defs[i].key);
free(p->defs[i].val);

72
contrib/mandoc/eqn.h Normal file
View File

@ -0,0 +1,72 @@
/* $Id: eqn.h,v 1.1 2018/12/13 05:23:38 schwarze Exp $ */
/*
* Copyright (c) 2011, 2014 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 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.
*
* Public data types for eqn(7) syntax trees.
*/
enum eqn_boxt {
EQN_TEXT, /* Text, e.g. number, variable, operator, ... */
EQN_SUBEXPR, /* Nested eqn(7) subexpression. */
EQN_LIST, /* List, for example in braces. */
EQN_PILE, /* Vertical pile. */
EQN_MATRIX /* List of columns. */
};
enum eqn_fontt {
EQNFONT_NONE = 0,
EQNFONT_ROMAN,
EQNFONT_BOLD,
EQNFONT_FAT,
EQNFONT_ITALIC,
EQNFONT__MAX
};
enum eqn_post {
EQNPOS_NONE = 0,
EQNPOS_SUP,
EQNPOS_SUBSUP,
EQNPOS_SUB,
EQNPOS_TO,
EQNPOS_FROM,
EQNPOS_FROMTO,
EQNPOS_OVER,
EQNPOS_SQRT,
EQNPOS__MAX
};
/*
* A "box" is a parsed mathematical expression as defined by the eqn.7
* grammar.
*/
struct eqn_box {
struct eqn_box *parent;
struct eqn_box *prev;
struct eqn_box *next;
struct eqn_box *first; /* First child node. */
struct eqn_box *last; /* Last child node. */
char *text; /* Text (or NULL). */
char *left; /* Left-hand fence. */
char *right; /* Right-hand fence. */
char *top; /* Symbol above. */
char *bottom; /* Symbol below. */
size_t expectargs; /* Maximal number of arguments. */
size_t args; /* Actual number of arguments. */
int size; /* Font size. */
#define EQN_DEFSIZE INT_MIN
enum eqn_boxt type; /* Type of node. */
enum eqn_fontt font; /* Font in this box. */
enum eqn_post pos; /* Position of the next box. */
};

View File

@ -1,4 +1,4 @@
/* $Id: eqn_html.c,v 1.17 2017/07/14 13:32:35 schwarze Exp $ */
/* $Id: eqn_html.c,v 1.18 2018/12/13 05:23:38 schwarze Exp $ */
/*
* Copyright (c) 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>
@ -26,6 +26,7 @@
#include <string.h>
#include "mandoc.h"
#include "eqn.h"
#include "out.h"
#include "html.h"

View File

@ -0,0 +1,48 @@
/* $Id: eqn_parse.h,v 1.3 2018/12/14 06:33:14 schwarze Exp $ */
/*
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014, 2017, 2018 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.
*
* External interface of the eqn(7) parser.
* For use in the roff(7) and eqn(7) parsers only.
*/
struct roff_node;
struct eqn_box;
struct eqn_def;
struct eqn_node {
struct roff_node *node; /* Syntax tree of this equation. */
struct eqn_def *defs; /* Array of definitions. */
char *data; /* Source code of this equation. */
char *start; /* First byte of the current token. */
char *end; /* First byte of the next token. */
size_t defsz; /* Number of definitions. */
size_t sz; /* Length of the source code. */
size_t toksz; /* Length of the current token. */
int gsize; /* Default point size. */
int delim; /* In-line delimiters enabled. */
char odelim; /* In-line opening delimiter. */
char cdelim; /* In-line closing delimiter. */
};
struct eqn_node *eqn_alloc(void);
struct eqn_box *eqn_box_new(void);
void eqn_box_free(struct eqn_box *);
void eqn_free(struct eqn_node *);
void eqn_parse(struct eqn_node *);
void eqn_read(struct eqn_node *, const char *);
void eqn_reset(struct eqn_node *);

View File

@ -1,4 +1,4 @@
/* $Id: eqn_term.c,v 1.17 2017/08/23 21:56:20 schwarze Exp $ */
/* $Id: eqn_term.c,v 1.19 2018/12/13 05:23:38 schwarze Exp $ */
/*
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
@ -25,7 +25,7 @@
#include <stdlib.h>
#include <string.h>
#include "mandoc.h"
#include "eqn.h"
#include "out.h"
#include "term.h"
@ -106,7 +106,7 @@ eqn_box(struct termp *p, const struct eqn_box *bp)
/* Special box types. */
if (bp->pos == EQNPOS_SQRT) {
term_word(p, "sqrt");
term_word(p, "\\(sr");
if (bp->first != NULL) {
p->flags |= TERMP_NOSPACE;
eqn_box(p, bp->first);

View File

@ -36,7 +36,7 @@ elif [ "X$1" = "X-u" ]; then
MOPT="-Ios=OpenBSD -Wall -Tutf8 $MOPT"
COLPIPE="cat"
else
ROFF="groff -et -ww -mtty-char -Tascii -P -c"
ROFF="groff -ket -ww -mtty-char -Tascii -P -c"
MOPT="-Ios=OpenBSD -Wall -Tascii $MOPT"
COLPIPE="cat"
fi
@ -51,7 +51,7 @@ while [ -n "$1" ]; do
for i in roff mandoc; do
[ -s /tmp/$i.err ] && echo "$i errors:" && cat /tmp/$i.err
done
diff -au /tmp/roff.out /tmp/mandoc.out 2>&1
diff -au $DIFFOPT /tmp/roff.out /tmp/mandoc.out 2>&1
done
exit 0

View File

@ -1,7 +1,7 @@
/* $Id: html.c,v 1.238 2018/06/25 16:54:59 schwarze Exp $ */
/* $Id: html.c,v 1.254 2019/03/03 13:02:11 schwarze Exp $ */
/*
* Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011-2015, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2011-2015, 2017-2019 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
@ -18,6 +18,7 @@
#include "config.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <assert.h>
#include <ctype.h>
@ -62,6 +63,7 @@ static const struct htmldata htmltags[TAG_MAX] = {
{"title", HTML_NLAROUND},
{"div", HTML_NLAROUND},
{"div", 0},
{"section", HTML_NLALL},
{"h1", HTML_NLAROUND},
{"h2", HTML_NLAROUND},
{"span", 0},
@ -77,6 +79,7 @@ static const struct htmldata htmltags[TAG_MAX] = {
{"dl", HTML_NLALL | HTML_INDENT},
{"dt", HTML_NLAROUND},
{"dd", HTML_NLAROUND | HTML_INDENT},
{"p", HTML_NLAROUND | HTML_INDENT},
{"pre", HTML_NLALL | HTML_NOINDENT},
{"var", 0},
{"cite", 0},
@ -107,6 +110,7 @@ static const struct htmldata htmltags[TAG_MAX] = {
/* Avoid duplicate HTML id= attributes. */
static struct ohash id_unique;
static void html_reset_internal(struct html *);
static void print_byte(struct html *, char);
static void print_endword(struct html *);
static void print_indent(struct html *);
@ -116,7 +120,6 @@ static void print_ctag(struct html *, struct tag *);
static int print_escape(struct html *, char);
static int print_encode(struct html *, const char *, const char *, int);
static void print_href(struct html *, const char *, const char *, int);
static void print_metaf(struct html *, enum mandoc_esc);
void *
@ -128,31 +131,32 @@ html_alloc(const struct manoutput *outopts)
h->tag = NULL;
h->style = outopts->style;
h->base_man = outopts->man;
if ((h->base_man1 = outopts->man) == NULL)
h->base_man2 = NULL;
else if ((h->base_man2 = strchr(h->base_man1, ';')) != NULL)
*h->base_man2++ = '\0';
h->base_includes = outopts->includes;
if (outopts->fragment)
h->oflags |= HTML_FRAGMENT;
if (outopts->toc)
h->oflags |= HTML_TOC;
mandoc_ohash_init(&id_unique, 4, 0);
return h;
}
void
html_free(void *p)
static void
html_reset_internal(struct html *h)
{
struct tag *tag;
struct html *h;
char *cp;
unsigned int slot;
h = (struct html *)p;
while ((tag = h->tag) != NULL) {
h->tag = tag->next;
free(tag);
}
free(h);
cp = ohash_first(&id_unique, &slot);
while (cp != NULL) {
free(cp);
@ -161,6 +165,20 @@ html_free(void *p)
ohash_delete(&id_unique);
}
void
html_reset(void *p)
{
html_reset_internal(p);
mandoc_ohash_init(&id_unique, 4, 0);
}
void
html_free(void *p)
{
html_reset_internal(p);
free(p);
}
void
print_gen_head(struct html *h)
{
@ -204,7 +222,7 @@ print_gen_head(struct html *h)
print_tagq(h, t);
}
static void
void
print_metaf(struct html *h, enum mandoc_esc deco)
{
enum htmlfont font;
@ -222,12 +240,15 @@ print_metaf(struct html *h, enum mandoc_esc deco)
case ESCAPE_FONTBI:
font = HTMLFONT_BI;
break;
case ESCAPE_FONTCW:
font = HTMLFONT_CW;
break;
case ESCAPE_FONT:
case ESCAPE_FONTROMAN:
font = HTMLFONT_NONE;
break;
default:
abort();
return;
}
if (h->metaf) {
@ -249,11 +270,69 @@ print_metaf(struct html *h, enum mandoc_esc deco)
h->metaf = print_otag(h, TAG_B, "");
print_otag(h, TAG_I, "");
break;
case HTMLFONT_CW:
h->metaf = print_otag(h, TAG_SPAN, "c", "Li");
break;
default:
break;
}
}
void
html_close_paragraph(struct html *h)
{
struct tag *t;
for (t = h->tag; t != NULL && t->closed == 0; t = t->next) {
switch(t->tag) {
case TAG_P:
case TAG_PRE:
print_tagq(h, t);
break;
case TAG_A:
print_tagq(h, t);
continue;
default:
continue;
}
break;
}
}
/*
* ROFF_nf switches to no-fill mode, ROFF_fi to fill mode.
* TOKEN_NONE does not switch. The old mode is returned.
*/
enum roff_tok
html_fillmode(struct html *h, enum roff_tok want)
{
struct tag *t;
enum roff_tok had;
for (t = h->tag; t != NULL; t = t->next)
if (t->tag == TAG_PRE)
break;
had = t == NULL ? ROFF_fi : ROFF_nf;
if (want != had) {
switch (want) {
case ROFF_fi:
print_tagq(h, t);
break;
case ROFF_nf:
html_close_paragraph(h);
print_otag(h, TAG_PRE, "");
break;
case TOKEN_NONE:
break;
default:
abort();
}
}
return had;
}
char *
html_make_id(const struct roff_node *n, int unique)
{
@ -345,7 +424,6 @@ static int
print_encode(struct html *h, const char *p, const char *pend, int norecurse)
{
char numbuf[16];
struct tag *t;
const char *seq;
size_t sz;
int c, len, breakline, nospace;
@ -371,9 +449,7 @@ print_encode(struct html *h, const char *p, const char *pend, int norecurse)
if (breakline &&
(p >= pend || *p == ' ' || *p == ASCII_NBRSP)) {
t = print_otag(h, TAG_DIV, "");
print_text(h, "\\~");
print_tagq(h, t);
print_otag(h, TAG_BR, "");
breakline = 0;
while (p < pend && (*p == ' ' || *p == ASCII_NBRSP))
p++;
@ -393,22 +469,25 @@ print_encode(struct html *h, const char *p, const char *pend, int norecurse)
continue;
esc = mandoc_escape(&p, &seq, &len);
if (ESCAPE_ERROR == esc)
break;
switch (esc) {
case ESCAPE_FONT:
case ESCAPE_FONTPREV:
case ESCAPE_FONTBOLD:
case ESCAPE_FONTITALIC:
case ESCAPE_FONTBI:
case ESCAPE_FONTCW:
case ESCAPE_FONTROMAN:
if (0 == norecurse)
if (0 == norecurse) {
h->flags |= HTML_NOSPACE;
print_metaf(h, esc);
h->flags &= ~HTML_NOSPACE;
}
continue;
case ESCAPE_SKIPCHAR:
h->flags |= HTML_SKIPCHAR;
continue;
case ESCAPE_ERROR:
continue;
default:
break;
}
@ -433,6 +512,12 @@ print_encode(struct html *h, const char *p, const char *pend, int norecurse)
if (c <= 0)
continue;
break;
case ESCAPE_UNDEF:
c = *seq;
break;
case ESCAPE_DEVICE:
print_word(h, "html");
continue;
case ESCAPE_BREAK:
breakline = 1;
continue;
@ -464,9 +549,21 @@ print_encode(struct html *h, const char *p, const char *pend, int norecurse)
static void
print_href(struct html *h, const char *name, const char *sec, int man)
{
struct stat sb;
const char *p, *pp;
char *filename;
if (man) {
pp = h->base_man1;
if (h->base_man2 != NULL) {
mandoc_asprintf(&filename, "%s.%s", name, sec);
if (stat(filename, &sb) == -1)
pp = h->base_man2;
free(filename);
}
} else
pp = h->base_includes;
pp = man ? h->base_man : h->base_includes;
while ((p = strchr(pp, '%')) != NULL) {
print_encode(h, pp, p, 1);
if (man && p[1] == 'S') {
@ -492,7 +589,7 @@ print_otag(struct html *h, enum htmltag tag, const char *fmt, ...)
struct tag *t;
const char *attr;
char *arg1, *arg2;
int tflags;
int style_written, tflags;
tflags = htmltags[tag].flags;
@ -502,6 +599,8 @@ print_otag(struct html *h, enum htmltag tag, const char *fmt, ...)
t = mandoc_malloc(sizeof(struct tag));
t->tag = tag;
t->next = h->tag;
t->refcnt = 0;
t->closed = 0;
h->tag = t;
} else
t = NULL;
@ -532,7 +631,7 @@ print_otag(struct html *h, enum htmltag tag, const char *fmt, ...)
va_start(ap, fmt);
while (*fmt != '\0') {
while (*fmt != '\0' && *fmt != 's') {
/* Parse attributes and arguments. */
@ -548,10 +647,6 @@ print_otag(struct html *h, enum htmltag tag, const char *fmt, ...)
case 'i':
attr = "id";
break;
case 's':
attr = "style";
arg2 = va_arg(ap, char *);
break;
case '?':
attr = arg1;
arg1 = va_arg(ap, char *);
@ -584,26 +679,33 @@ print_otag(struct html *h, enum htmltag tag, const char *fmt, ...)
print_encode(h, arg1, NULL, 1);
fmt++;
break;
case 'T':
print_encode(h, arg1, NULL, 1);
print_word(h, "\" title=\"");
print_encode(h, arg1, NULL, 1);
fmt++;
break;
default:
if (arg2 == NULL)
print_encode(h, arg1, NULL, 1);
else {
print_word(h, arg1);
print_byte(h, ':');
print_byte(h, ' ');
print_word(h, arg2);
print_byte(h, ';');
}
print_encode(h, arg1, NULL, 1);
break;
}
print_byte(h, '"');
}
style_written = 0;
while (*fmt++ == 's') {
arg1 = va_arg(ap, char *);
arg2 = va_arg(ap, char *);
if (arg2 == NULL)
continue;
print_byte(h, ' ');
if (style_written == 0) {
print_word(h, "style=\"");
style_written = 1;
}
print_word(h, arg1);
print_byte(h, ':');
print_byte(h, ' ');
print_word(h, arg2);
print_byte(h, ';');
}
if (style_written)
print_byte(h, '"');
va_end(ap);
/* Accommodate for "well-formed" singleton escaping. */
@ -631,33 +733,32 @@ print_ctag(struct html *h, struct tag *tag)
{
int tflags;
/*
* 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;
if (tag->closed == 0) {
tag->closed = 1;
if (tag == h->metaf)
h->metaf = NULL;
if (tag == h->tblt)
h->tblt = NULL;
tflags = htmltags[tag->tag].flags;
if (tflags & HTML_INDENT)
h->indent--;
if (tflags & HTML_NOINDENT)
h->noindent--;
if (tflags & HTML_NLEND)
print_endline(h);
print_indent(h);
print_byte(h, '<');
print_byte(h, '/');
print_word(h, htmltags[tag->tag].name);
print_byte(h, '>');
if (tflags & HTML_NLAFTER)
print_endline(h);
h->tag = tag->next;
free(tag);
tflags = htmltags[tag->tag].flags;
if (tflags & HTML_INDENT)
h->indent--;
if (tflags & HTML_NOINDENT)
h->noindent--;
if (tflags & HTML_NLEND)
print_endline(h);
print_indent(h);
print_byte(h, '<');
print_byte(h, '/');
print_word(h, htmltags[tag->tag].name);
print_byte(h, '>');
if (tflags & HTML_NLAFTER)
print_endline(h);
}
if (tag->refcnt == 0) {
h->tag = tag->next;
free(tag);
}
}
void
@ -717,6 +818,9 @@ print_text(struct html *h, const char *word)
h->metaf = print_otag(h, TAG_B, "");
print_otag(h, TAG_I, "");
break;
case HTMLFONT_CW:
h->metaf = print_otag(h, TAG_SPAN, "c", "Li");
break;
default:
print_indent(h);
break;
@ -741,36 +845,33 @@ print_text(struct html *h, const char *word)
void
print_tagq(struct html *h, const struct tag *until)
{
struct tag *tag;
struct tag *this, *next;
while ((tag = h->tag) != NULL) {
print_ctag(h, tag);
if (until && tag == until)
return;
for (this = h->tag; this != NULL; this = next) {
next = this == until ? NULL : this->next;
print_ctag(h, this);
}
}
/*
* Close out all open elements up to but excluding suntil.
* Note that a paragraph just inside stays open together with it
* because paragraphs include subsequent phrasing content.
*/
void
print_stagq(struct html *h, const struct tag *suntil)
{
struct tag *tag;
struct tag *this, *next;
while ((tag = h->tag) != NULL) {
if (suntil && tag == suntil)
return;
print_ctag(h, tag);
for (this = h->tag; this != NULL; this = next) {
next = this->next;
if (this == suntil || (next == suntil &&
(this->tag == TAG_P || this->tag == TAG_PRE)))
break;
print_ctag(h, this);
}
}
void
print_paragraph(struct html *h)
{
struct tag *t;
t = print_otag(h, TAG_DIV, "c", "Pp");
print_tagq(h, t);
}
/***********************************************************************
* Low level output functions.

View File

@ -1,7 +1,7 @@
/* $Id: html.h,v 1.92 2018/06/25 16:54:59 schwarze Exp $ */
/* $Id: html.h,v 1.102 2019/03/01 10:57:18 schwarze Exp $ */
/*
* Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2017, 2018, 2019 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
@ -24,6 +24,7 @@ enum htmltag {
TAG_TITLE,
TAG_DIV,
TAG_IDIV,
TAG_SECTION,
TAG_H1,
TAG_H2,
TAG_SPAN,
@ -39,6 +40,7 @@ enum htmltag {
TAG_DL,
TAG_DT,
TAG_DD,
TAG_P,
TAG_PRE,
TAG_VAR,
TAG_CITE,
@ -72,11 +74,14 @@ enum htmlfont {
HTMLFONT_BOLD,
HTMLFONT_ITALIC,
HTMLFONT_BI,
HTMLFONT_CW,
HTMLFONT_MAX
};
struct tag {
struct tag *next;
int refcnt;
int closed;
enum htmltag tag;
};
@ -87,12 +92,12 @@ struct html {
#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 */
#define HTML_SKIPCHAR (1 << 6) /* skip the next character */
#define HTML_NOSPLIT (1 << 7) /* do not break line before .An */
#define HTML_SPLIT (1 << 8) /* break line before .An */
#define HTML_NONEWLINE (1 << 9) /* No line break in nofill mode. */
#define HTML_BUFFER (1 << 10) /* Collect a word to see if it fits. */
#define HTML_TOCDONE (1 << 11) /* The TOC was already written. */
size_t indent; /* current output indentation level */
int noindent; /* indent disabled by <pre> */
size_t col; /* current output byte position */
@ -101,7 +106,8 @@ struct html {
struct tag *tag; /* last open tag */
struct rofftbl tbl; /* current table */
struct tag *tblt; /* current open table scope */
char *base_man; /* base for manpage href */
char *base_man1; /* bases for manpage href */
char *base_man2;
char *base_includes; /* base for include href */
char *style; /* style-sheet URI */
struct tag *metaf; /* current open font scope */
@ -109,6 +115,7 @@ struct html {
enum htmlfont metac; /* current font mode */
int oflags; /* output options */
#define HTML_FRAGMENT (1 << 0) /* don't emit HTML/HEAD/BODY */
#define HTML_TOC (1 << 1) /* emit a table of contents */
};
@ -121,6 +128,7 @@ void roff_html_pre(struct html *, const struct roff_node *);
void print_gen_comment(struct html *, struct roff_node *);
void print_gen_decls(struct html *);
void print_gen_head(struct html *);
void print_metaf(struct html *, enum mandoc_esc);
struct tag *print_otag(struct html *, enum htmltag, const char *, ...);
void print_tagq(struct html *, const struct tag *);
void print_stagq(struct html *, const struct tag *);
@ -128,7 +136,8 @@ 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_box *);
void print_paragraph(struct html *);
void print_endline(struct html *);
void html_close_paragraph(struct html *);
enum roff_tok html_fillmode(struct html *, enum roff_tok);
char *html_make_id(const struct roff_node *, int);

View File

@ -1,4 +1,4 @@
/* $Id: lib.c,v 1.14 2017/06/24 14:38:32 schwarze Exp $ */
/* $Id: lib.c,v 1.15 2018/12/13 11:55:46 schwarze Exp $ */
/*
* Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
*
@ -17,12 +17,9 @@
#include "config.h"
#include <sys/types.h>
#include <string.h>
#include "mandoc.h"
#include "roff.h"
#include "mdoc.h"
#include "libmdoc.h"
#define LINE(x, y) \

View File

@ -1,4 +1,4 @@
/* $Id: lib.in,v 1.20 2017/08/20 02:30:27 schwarze Exp $ */
/* $Id: lib.in,v 1.21 2019/03/04 17:35:21 schwarze Exp $ */
/*
* Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2009, 2012 Joerg Sonnenberger <joerg@netbsd.org>

View File

@ -1,7 +1,7 @@
/* $Id: libman.h,v 1.81 2017/04/29 12:45:41 schwarze Exp $ */
/* $Id: libman.h,v 1.86 2018/12/31 10:04:39 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2014, 2015, 2018 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
@ -16,6 +16,9 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
struct roff_node;
struct roff_man;
#define MACRO_PROT_ARGS struct roff_man *man, \
enum roff_tok tok, \
int line, \
@ -26,15 +29,14 @@
struct man_macro {
void (*fp)(MACRO_PROT_ARGS);
int flags;
#define MAN_SCOPED (1 << 0) /* Optional next-line scope. */
#define MAN_NSCOPED (1 << 1) /* Allowed in next-line element scope. */
#define MAN_BSCOPE (1 << 2) /* Break next-line block scope. */
#define MAN_JOIN (1 << 3) /* Join arguments together. */
#define MAN_BSCOPED (1 << 0) /* Optional next-line block scope. */
#define MAN_ESCOPED (1 << 1) /* Optional next-line element scope. */
#define MAN_NSCOPED (1 << 2) /* Allowed in next-line element scope. */
#define MAN_XSCOPE (1 << 3) /* Exit next-line block scope. */
#define MAN_JOIN (1 << 4) /* Join arguments together. */
};
extern const struct man_macro *const man_macros;
const struct man_macro *man_macro(enum roff_tok);
void man_node_validate(struct roff_man *);
void man_state(struct roff_man *, struct roff_node *);
void man_descope(struct roff_man *, int, int, char *);
void man_unscope(struct roff_man *, const struct roff_node *);

View File

@ -1,7 +1,7 @@
/* $Id: libmandoc.h,v 1.71 2018/04/09 22:27:04 schwarze Exp $ */
/* $Id: libmandoc.h,v 1.77 2018/12/21 17:15:18 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2013,2014,2015,2017,2018 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
@ -16,31 +16,38 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
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 */
};
/*
* Return codes passed from the roff parser to the main parser.
*/
/* Main instruction: what to do with the returned line. */
#define ROFF_IGN 0x000 /* Don't do anything with it. */
#define ROFF_CONT 0x001 /* Give it to the high-level parser. */
#define ROFF_RERUN 0x002 /* Re-run the roff parser with an offset. */
#define ROFF_REPARSE 0x004 /* Recursively run the main parser on it. */
#define ROFF_SO 0x008 /* Include the named file. */
#define ROFF_MASK 0x00f /* Only one of these bits should be set. */
/* Options for further parsing, to be OR'ed with the above. */
#define ROFF_APPEND 0x010 /* Append the next line to this one. */
#define ROFF_USERCALL 0x020 /* Start execution of a new macro. */
#define ROFF_USERRET 0x040 /* Abort execution of the current macro. */
#define ROFF_WHILE 0x100 /* Start a new .while loop. */
#define ROFF_LOOPCONT 0x200 /* Iterate the current .while loop. */
#define ROFF_LOOPEXIT 0x400 /* Exit the current .while loop. */
#define ROFF_LOOPMASK 0xf00
struct buf {
char *buf;
size_t sz;
char *buf;
size_t sz;
struct buf *next;
};
struct mparse;
struct roff;
struct roff_man;
void mandoc_msg(enum mandocerr, struct mparse *,
int, int, const char *);
void mandoc_vmsg(enum mandocerr, struct mparse *,
int, int, const char *, ...)
__attribute__((__format__ (__printf__, 5, 6)));
char *mandoc_getarg(struct mparse *, char **, int, int *);
char *mandoc_normdate(struct roff_man *, char *, int, int);
int mandoc_eos(const char *, size_t);
int mandoc_strntoi(const char *, size_t, int);
@ -57,17 +64,18 @@ int preconv_encode(const struct buf *, size_t *,
struct buf *, size_t *, int *);
void roff_free(struct roff *);
struct roff *roff_alloc(struct mparse *, int);
struct roff *roff_alloc(int);
void roff_reset(struct roff *);
void roff_man_free(struct roff_man *);
struct roff_man *roff_man_alloc(struct roff *, struct mparse *,
const char *, int);
struct roff_man *roff_man_alloc(struct roff *, const char *, int);
void roff_man_reset(struct roff_man *);
enum rofferr roff_parseln(struct roff *, int, struct buf *, int *);
int roff_parseln(struct roff *, int, struct buf *, int *);
void roff_userret(struct roff *);
void roff_endparse(struct roff *);
void roff_setreg(struct roff *, const char *, int, char sign);
int roff_getreg(struct roff *, const char *);
char *roff_strdup(const struct roff *, const char *);
char *roff_getarg(struct roff *, char **, int, int *);
int roff_getcontrol(const struct roff *,
const char *, int *);
int roff_getformat(const struct roff *);

View File

@ -1,7 +1,7 @@
/* $Id: libmdoc.h,v 1.112 2017/05/30 16:22:03 schwarze Exp $ */
/* $Id: libmdoc.h,v 1.117 2018/12/31 04:55:46 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2013,2014,2015,2017,2018 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
@ -16,6 +16,10 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
struct roff_node;
struct roff_man;
struct mdoc_arg;
#define MACRO_PROT_ARGS struct roff_man *mdoc, \
enum roff_tok tok, \
int line, \
@ -38,6 +42,7 @@ enum margserr {
ARGS_ERROR,
ARGS_EOLN, /* end-of-line */
ARGS_WORD, /* normal word */
ARGS_ALLOC, /* normal word from roff_getarg() */
ARGS_PUNCT, /* series of punctuation */
ARGS_PHRASE /* Bl -column phrase */
};
@ -59,10 +64,8 @@ enum mdelim {
DELIM_MAX
};
extern const struct mdoc_macro *const mdoc_macros;
const struct mdoc_macro *mdoc_macro(enum roff_tok);
void mdoc_macro(MACRO_PROT_ARGS);
void mdoc_elem_alloc(struct roff_man *, int, int,
enum roff_tok, struct mdoc_arg *);
struct roff_node *mdoc_block_alloc(struct roff_man *, int, int,
@ -71,10 +74,7 @@ void mdoc_tail_alloc(struct roff_man *, int, int,
enum roff_tok);
struct roff_node *mdoc_endbody_alloc(struct roff_man *, int, int,
enum roff_tok, struct roff_node *);
void mdoc_node_relink(struct roff_man *, struct roff_node *);
void mdoc_node_validate(struct roff_man *);
void mdoc_state(struct roff_man *, struct roff_node *);
void mdoc_state_reset(struct roff_man *);
const char *mdoc_a2arch(const char *);
const char *mdoc_a2att(const char *);
const char *mdoc_a2lib(const char *);

View File

@ -1,7 +1,7 @@
/* $Id: main.c,v 1.306 2018/05/14 14:10:23 schwarze Exp $ */
/* $Id: main.c,v 1.322 2019/03/06 10:18:58 schwarze Exp $ */
/*
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010-2012, 2014-2018 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2010-2012, 2014-2019 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2010 Joerg Sonnenberger <joerg@netbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
@ -49,6 +49,7 @@
#include "roff.h"
#include "mdoc.h"
#include "man.h"
#include "mandoc_parse.h"
#include "tag.h"
#include "main.h"
#include "manconf.h"
@ -81,7 +82,6 @@ struct curparse {
void *outdata; /* data for output */
char *os_s; /* operating system for display */
int wstop; /* stop after a file with a warning */
enum mandocerr mmin; /* ignore messages below this */
enum mandoc_os os_e; /* check base system conventions */
enum outt outtype; /* which output to use */
};
@ -89,7 +89,7 @@ struct curparse {
int mandocdb(int, char *[]);
static void check_xr(const char *);
static void check_xr(void);
static int fs_lookup(const struct manpaths *,
size_t ipath, const char *,
const char *, const char *,
@ -99,8 +99,6 @@ static int fs_search(const struct mansearch *,
struct manpage **, size_t *);
static int koptions(int *, char *);
static void moptions(int *, char *);
static void mmsg(enum mandocerr, enum mandoclevel,
const char *, int, int, const char *);
static void outdata_alloc(struct curparse *);
static void parse(struct curparse *, int, const char *);
static void passthrough(const char *, int, int);
@ -112,8 +110,6 @@ static int woptions(struct curparse *, char *);
static const int sec_prios[] = {1, 4, 5, 8, 6, 3, 7, 2, 9};
static char help_arg[] = "help";
static char *help_argv[] = {help_arg, NULL};
static enum mandoclevel rc;
static FILE *mmsg_stream;
int
@ -127,7 +123,7 @@ main(int argc, char *argv[])
struct manpage *res, *resp;
const char *progname, *sec, *thisarg;
char *conf_file, *defpaths, *auxpaths;
char *oarg;
char *oarg, *tagarg;
unsigned char *uc;
size_t i, sz;
int prio, best_prio;
@ -152,6 +148,7 @@ main(int argc, char *argv[])
setprogname(progname);
#endif
mandoc_msg_setoutfile(stderr);
if (strncmp(progname, "mandocdb", 8) == 0 ||
strcmp(progname, BINM_MAKEWHATIS) == 0)
return mandocdb(argc, argv);
@ -191,10 +188,8 @@ main(int argc, char *argv[])
memset(&curp, 0, sizeof(struct curparse));
curp.outtype = OUTT_LOCALE;
curp.mmin = MANDOCERR_MAX;
curp.outopts = &conf.output;
options = MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1;
mmsg_stream = stderr;
use_pager = 1;
tag_files = NULL;
@ -320,6 +315,9 @@ main(int argc, char *argv[])
}
}
if (curp.outtype != OUTT_TREE || !curp.outopts->noval)
options |= MPARSE_VALIDATE;
if (outmode == OUTMODE_FLN ||
outmode == OUTMODE_LST ||
!isatty(STDOUT_FILENO))
@ -377,7 +375,16 @@ main(int argc, char *argv[])
#endif
}
rc = MANDOCLEVEL_OK;
/*
* Use the first argument for -O tag in addition to
* using it as a search term for man(1) or apropos(1).
*/
if (conf.output.tag != NULL && *conf.output.tag == '\0') {
tagarg = argc > 0 && search.argmode == ARG_EXPR ?
strchr(*argv, '=') : NULL;
conf.output.tag = tagarg == NULL ? *argv : tagarg + 1;
}
/* man(1), whatis(1), apropos(1) */
@ -436,7 +443,6 @@ main(int argc, char *argv[])
res[sz].names = NULL;
res[sz].output = NULL;
res[sz].ipath = SIZE_MAX;
res[sz].bits = 0;
res[sz].sec = 10;
res[sz].form = FORM_SRC;
sz++;
@ -446,7 +452,7 @@ main(int argc, char *argv[])
if (sz == 0) {
if (search.argmode != ARG_NAME)
warnx("nothing appropriate");
rc = MANDOCLEVEL_BADARG;
mandoc_msg_setrc(MANDOCLEVEL_BADARG);
goto out;
}
@ -514,19 +520,17 @@ main(int argc, char *argv[])
moptions(&options, auxpaths);
mchars_alloc();
curp.mp = mparse_alloc(options, curp.mmin, mmsg,
curp.os_e, curp.os_s);
/*
* Conditionally start up the lookaside buffer before parsing.
*/
if (OUTT_MAN == curp.outtype)
mparse_keep(curp.mp);
curp.mp = mparse_alloc(options, curp.os_e, curp.os_s);
if (argc < 1) {
if (use_pager)
if (use_pager) {
tag_files = tag_init();
parse(&curp, STDIN_FILENO, "<stdin>");
tag_files->tagname = conf.output.tag;
}
thisarg = "<stdin>";
mandoc_msg_setinfilename(thisarg);
parse(&curp, STDIN_FILENO, thisarg);
mandoc_msg_setinfilename(NULL);
}
/*
@ -550,22 +554,25 @@ main(int argc, char *argv[])
(void)chdir(conf.manpath.paths[resp->ipath]);
else if (startdir != -1)
(void)fchdir(startdir);
}
thisarg = resp->file;
} else
thisarg = *argv;
fd = mparse_open(curp.mp, resp != NULL ? resp->file : *argv);
fd = mparse_open(curp.mp, thisarg);
if (fd != -1) {
if (use_pager) {
tag_files = tag_init();
use_pager = 0;
tag_files = tag_init();
tag_files->tagname = conf.output.tag;
}
if (resp == NULL)
parse(&curp, fd, *argv);
else if (resp->form == FORM_SRC)
parse(&curp, fd, resp->file);
mandoc_msg_setinfilename(thisarg);
if (resp == NULL || resp->form == FORM_SRC)
parse(&curp, fd, thisarg);
else
passthrough(resp->file, fd,
conf.output.synopsisonly);
mandoc_msg_setinfilename(NULL);
if (ferror(stdout)) {
if (tag_files != NULL) {
@ -574,7 +581,7 @@ main(int argc, char *argv[])
tag_files = NULL;
} else
warn("stdout");
rc = MANDOCLEVEL_SYSERR;
mandoc_msg_setrc(MANDOCLEVEL_SYSERR);
break;
}
@ -583,10 +590,11 @@ main(int argc, char *argv[])
outdata_alloc(&curp);
terminal_sepline(curp.outdata);
}
} else if (rc < MANDOCLEVEL_ERROR)
rc = MANDOCLEVEL_ERROR;
} else
mandoc_msg(MANDOCERR_FILE, 0, 0,
"%s: %s", thisarg, strerror(errno));
if (MANDOCLEVEL_OK != rc && curp.wstop)
if (curp.wstop && mandoc_msg_getrc() != MANDOCLEVEL_OK)
break;
if (resp != NULL)
@ -677,7 +685,7 @@ main(int argc, char *argv[])
if (pid == -1) {
warn("wait");
rc = MANDOCLEVEL_SYSERR;
mandoc_msg_setrc(MANDOCLEVEL_SYSERR);
break;
}
if (!WIFSTOPPED(status))
@ -687,8 +695,7 @@ main(int argc, char *argv[])
}
tag_unlink();
}
return (int)rc;
return (int)mandoc_msg_getrc();
}
static void
@ -786,7 +793,6 @@ fs_lookup(const struct manpaths *paths, size_t ipath,
page->names = NULL;
page->output = NULL;
page->ipath = ipath;
page->bits = NAME_FILE & NAME_MASK;
page->sec = (*sec >= '1' && *sec <= '9') ? *sec - '1' + 1 : 10;
page->form = form;
return 1;
@ -821,8 +827,18 @@ fs_search(const struct mansearch *cfg, const struct manpaths *paths,
return 1;
}
if (res != NULL && *ressz == lastsz &&
strchr(*argv, '/') == NULL)
warnx("No entry for %s in the manual.", *argv);
strchr(*argv, '/') == NULL) {
if (cfg->arch != NULL &&
arch_valid(cfg->arch, OSENUM) == 0)
warnx("Unknown architecture \"%s\".",
cfg->arch);
else if (cfg->sec == NULL)
warnx("No entry for %s in the manual.",
*argv);
else
warnx("No entry for %s in section %s "
"of the manual.", *argv, cfg->sec);
}
lastsz = *ressz;
argv++;
argc--;
@ -833,101 +849,92 @@ fs_search(const struct mansearch *cfg, const struct manpaths *paths,
static void
parse(struct curparse *curp, int fd, const char *file)
{
enum mandoclevel rctmp;
struct roff_man *man;
struct roff_meta *meta;
/* Begin by parsing the file itself. */
assert(file);
assert(fd >= 0);
rctmp = mparse_readfd(curp->mp, fd, file);
mparse_readfd(curp->mp, fd, file);
if (fd != STDIN_FILENO)
close(fd);
if (rc < rctmp)
rc = rctmp;
/*
* With -Wstop and warnings or errors of at least the requested
* level, do not produce output.
*/
if (rctmp != MANDOCLEVEL_OK && curp->wstop)
if (curp->wstop && mandoc_msg_getrc() != MANDOCLEVEL_OK)
return;
if (curp->outdata == NULL)
outdata_alloc(curp);
else if (curp->outtype == OUTT_HTML)
html_reset(curp);
mparse_result(curp->mp, &man, NULL);
mandoc_xr_reset();
meta = mparse_result(curp->mp);
/* Execute the out device, if it exists. */
if (man == NULL)
return;
mandoc_xr_reset();
if (man->macroset == MACROSET_MDOC) {
if (curp->outtype != OUTT_TREE || !curp->outopts->noval)
mdoc_validate(man);
if (meta->macroset == MACROSET_MDOC) {
switch (curp->outtype) {
case OUTT_HTML:
html_mdoc(curp->outdata, man);
html_mdoc(curp->outdata, meta);
break;
case OUTT_TREE:
tree_mdoc(curp->outdata, man);
tree_mdoc(curp->outdata, meta);
break;
case OUTT_MAN:
man_mdoc(curp->outdata, man);
man_mdoc(curp->outdata, meta);
break;
case OUTT_PDF:
case OUTT_ASCII:
case OUTT_UTF8:
case OUTT_LOCALE:
case OUTT_PS:
terminal_mdoc(curp->outdata, man);
terminal_mdoc(curp->outdata, meta);
break;
case OUTT_MARKDOWN:
markdown_mdoc(curp->outdata, man);
markdown_mdoc(curp->outdata, meta);
break;
default:
break;
}
}
if (man->macroset == MACROSET_MAN) {
if (curp->outtype != OUTT_TREE || !curp->outopts->noval)
man_validate(man);
if (meta->macroset == MACROSET_MAN) {
switch (curp->outtype) {
case OUTT_HTML:
html_man(curp->outdata, man);
html_man(curp->outdata, meta);
break;
case OUTT_TREE:
tree_man(curp->outdata, man);
tree_man(curp->outdata, meta);
break;
case OUTT_MAN:
man_man(curp->outdata, man);
mparse_copy(curp->mp);
break;
case OUTT_PDF:
case OUTT_ASCII:
case OUTT_UTF8:
case OUTT_LOCALE:
case OUTT_PS:
terminal_man(curp->outdata, man);
terminal_man(curp->outdata, meta);
break;
default:
break;
}
}
if (curp->mmin < MANDOCERR_STYLE)
check_xr(file);
mparse_updaterc(curp->mp, &rc);
if (mandoc_msg_getmin() < MANDOCERR_STYLE)
check_xr();
}
static void
check_xr(const char *file)
check_xr(void)
{
static struct manpaths paths;
struct mansearch search;
struct mandoc_xr *xr;
char *cp;
size_t sz;
if (paths.sz == 0)
@ -946,13 +953,12 @@ check_xr(const char *file)
if (fs_search(&search, &paths, 1, &xr->name, NULL, &sz))
continue;
if (xr->count == 1)
mandoc_asprintf(&cp, "Xr %s %s", xr->name, xr->sec);
mandoc_msg(MANDOCERR_XR_BAD, xr->line,
xr->pos + 1, "Xr %s %s", xr->name, xr->sec);
else
mandoc_asprintf(&cp, "Xr %s %s (%d times)",
mandoc_msg(MANDOCERR_XR_BAD, xr->line,
xr->pos + 1, "Xr %s %s (%d times)",
xr->name, xr->sec, xr->count);
mmsg(MANDOCERR_XR_BAD, MANDOCLEVEL_STYLE,
file, xr->line, xr->pos + 1, cp);
free(cp);
}
}
@ -1051,8 +1057,7 @@ passthrough(const char *file, int fd, int synopsis_only)
fail:
free(line);
warn("%s: SYSERR: %s", file, syscall);
if (rc < MANDOCLEVEL_SYSERR)
rc = MANDOCLEVEL_SYSERR;
mandoc_msg_setrc(MANDOCLEVEL_SYSERR);
}
static int
@ -1094,8 +1099,8 @@ toptions(struct curparse *curp, char *arg)
curp->outtype = OUTT_ASCII;
else if (0 == strcmp(arg, "lint")) {
curp->outtype = OUTT_LINT;
curp->mmin = MANDOCERR_BASE;
mmsg_stream = stdout;
mandoc_msg_setoutfile(stdout);
mandoc_msg_setmin(MANDOCERR_BASE);
} else if (0 == strcmp(arg, "tree"))
curp->outtype = OUTT_TREE;
else if (0 == strcmp(arg, "man"))
@ -1146,29 +1151,29 @@ woptions(struct curparse *curp, char *arg)
break;
case 1:
case 2:
curp->mmin = MANDOCERR_BASE;
mandoc_msg_setmin(MANDOCERR_BASE);
break;
case 3:
curp->mmin = MANDOCERR_STYLE;
mandoc_msg_setmin(MANDOCERR_STYLE);
break;
case 4:
curp->mmin = MANDOCERR_WARNING;
mandoc_msg_setmin(MANDOCERR_WARNING);
break;
case 5:
curp->mmin = MANDOCERR_ERROR;
mandoc_msg_setmin(MANDOCERR_ERROR);
break;
case 6:
curp->mmin = MANDOCERR_UNSUPP;
mandoc_msg_setmin(MANDOCERR_UNSUPP);
break;
case 7:
curp->mmin = MANDOCERR_MAX;
mandoc_msg_setmin(MANDOCERR_MAX);
break;
case 8:
curp->mmin = MANDOCERR_BASE;
mandoc_msg_setmin(MANDOCERR_BASE);
curp->os_e = MANDOC_OS_OPENBSD;
break;
case 9:
curp->mmin = MANDOCERR_BASE;
mandoc_msg_setmin(MANDOCERR_BASE);
curp->os_e = MANDOC_OS_NETBSD;
break;
default:
@ -1179,29 +1184,6 @@ woptions(struct curparse *curp, char *arg)
return 1;
}
static void
mmsg(enum mandocerr t, enum mandoclevel lvl,
const char *file, int line, int col, const char *msg)
{
const char *mparse_msg;
fprintf(mmsg_stream, "%s: %s:", getprogname(),
file == NULL ? "<stdin>" : file);
if (line)
fprintf(mmsg_stream, "%d:%d:", line, col + 1);
fprintf(mmsg_stream, " %s", mparse_strlevel(lvl));
if ((mparse_msg = mparse_strerror(t)) != NULL)
fprintf(mmsg_stream, ": %s", mparse_msg);
if (msg)
fprintf(mmsg_stream, ": %s", msg);
fputc('\n', mmsg_stream);
}
static pid_t
spawn_pager(struct tag_files *tag_files)
{
@ -1210,8 +1192,10 @@ spawn_pager(struct tag_files *tag_files)
char *argv[MAX_PAGER_ARGS];
const char *pager;
char *cp;
#if HAVE_LESS_T
size_t cmdlen;
int argc;
#endif
int argc, use_ofn;
pid_t pager_pid;
pager = getenv("MANPAGER");
@ -1227,7 +1211,7 @@ spawn_pager(struct tag_files *tag_files)
*/
argc = 0;
while (argc + 4 < MAX_PAGER_ARGS) {
while (argc + 5 < MAX_PAGER_ARGS) {
argv[argc++] = cp;
cp = strchr(cp, ' ');
if (cp == NULL)
@ -1241,14 +1225,23 @@ spawn_pager(struct tag_files *tag_files)
/* For less(1), use the tag file. */
use_ofn = 1;
#if HAVE_LESS_T
if ((cmdlen = strlen(argv[0])) >= 4) {
cp = argv[0] + cmdlen - 4;
if (strcmp(cp, "less") == 0) {
argv[argc++] = mandoc_strdup("-T");
argv[argc++] = tag_files->tfn;
if (tag_files->tagname != NULL) {
argv[argc++] = mandoc_strdup("-t");
argv[argc++] = tag_files->tagname;
use_ofn = 0;
}
}
}
argv[argc++] = tag_files->ofn;
#endif
if (use_ofn)
argv[argc++] = tag_files->ofn;
argv[argc] = NULL;
switch (pager_pid = fork()) {

View File

@ -1,7 +1,7 @@
/* $Id: main.h,v 1.27 2017/03/03 14:23:23 schwarze Exp $ */
/* $Id: main.h,v 1.30 2019/03/03 13:02:11 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2014, 2015, 2019 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
@ -16,7 +16,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
struct roff_man;
struct roff_meta;
struct manoutput;
/*
@ -27,15 +27,15 @@ struct manoutput;
*/
void *html_alloc(const struct manoutput *);
void html_mdoc(void *, const struct roff_man *);
void html_man(void *, const struct roff_man *);
void html_mdoc(void *, const struct roff_meta *);
void html_man(void *, const struct roff_meta *);
void html_reset(void *);
void html_free(void *);
void tree_mdoc(void *, const struct roff_man *);
void tree_man(void *, const struct roff_man *);
void tree_mdoc(void *, const struct roff_meta *);
void tree_man(void *, const struct roff_meta *);
void man_mdoc(void *, const struct roff_man *);
void man_man(void *, const struct roff_man *);
void man_mdoc(void *, const struct roff_meta *);
void *locale_alloc(const struct manoutput *);
void *utf8_alloc(const struct manoutput *);
@ -46,8 +46,8 @@ void *pdf_alloc(const struct manoutput *);
void *ps_alloc(const struct manoutput *);
void pspdf_free(void *);
void terminal_mdoc(void *, const struct roff_man *);
void terminal_man(void *, const struct roff_man *);
void terminal_mdoc(void *, const struct roff_meta *);
void terminal_man(void *, const struct roff_meta *);
void terminal_sepline(void *);
void markdown_mdoc(void *, const struct roff_man *);
void markdown_mdoc(void *, const struct roff_meta *);

View File

@ -1,9 +1,9 @@
.\" $Id: man.1,v 1.33 2018/04/19 23:41:16 schwarze Exp $
.\" $Id: man.1,v 1.35 2019/03/09 15:55:01 schwarze Exp $
.\"
.\" Copyright (c) 1989, 1990, 1993
.\" The Regents of the University of California. All rights reserved.
.\" Copyright (c) 2003, 2007, 2008, 2014 Jason McIntyre <jmc@openbsd.org>
.\" Copyright (c) 2010, 2011, 2014-2017 Ingo Schwarze <schwarze@openbsd.org>
.\" Copyright (c) 2010, 2011, 2014-2018 Ingo Schwarze <schwarze@openbsd.org>
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
@ -31,7 +31,7 @@
.\"
.\" @(#)man.1 8.2 (Berkeley) 1/2/94
.\"
.Dd $Mdocdate: April 19 2018 $
.Dd $Mdocdate: March 9 2019 $
.Dt MAN 1
.Os
.Sh NAME
@ -218,12 +218,24 @@ Guidelines for writing
man pages can be found in
.Xr mdoc 7 .
.Pp
The
.Xr mandoc.db 5
database is used for looking up manual page entries.
In cases where the database is absent, outdated, or corrupt,
.Nm
falls back to looking for files called
.Ar name . Ns Ar section .
If both a formatted and an unformatted version of the same manual page,
for example
.Pa cat1/foo.0
and
.Pa man1/foo.1 ,
exist in the same directory, only the unformatted version is used.
The database is kept up to date with
.Xr makewhatis 8 ,
which is run by the
.Xr weekly 8
maintenance script.
.Sh ENVIRONMENT
.Bl -tag -width MANPATHX
.It Ev MACHINE
@ -266,6 +278,13 @@ and
can be used to move to the next and to the previous place providing
information about the term last searched for with
.Ic :t .
The
.Fl O Cm tag Ns Op = Ns Ar term
option documented in the
.Xr mandoc 1
manual opens a manual page at the definition of a specific
.Ar term
rather than at the beginning.
.It Ev MANPATH
The standard search path used by
.Nm

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
/* $Id: man.c,v 1.176 2017/06/28 12:52:45 schwarze Exp $ */
/* $Id: man.c,v 1.187 2019/01/05 00:36:50 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2013-2015, 2017-2019 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2011 Joerg Sonnenberger <joerg@netbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
@ -35,7 +35,7 @@
#include "roff_int.h"
#include "libman.h"
static void man_descope(struct roff_man *, int, int);
static char *man_hasc(char *);
static int man_ptext(struct roff_man *, int, char *, int);
static int man_pmacro(struct roff_man *, int, char *, int);
@ -52,38 +52,62 @@ man_parseln(struct roff_man *man, int ln, char *buf, int offs)
man_ptext(man, ln, buf, offs);
}
static void
man_descope(struct roff_man *man, int line, int offs)
/*
* If the string ends with \c, return a pointer to the backslash.
* Otherwise, return NULL.
*/
static char *
man_hasc(char *start)
{
char *cp, *ep;
ep = strchr(start, '\0') - 2;
if (ep < start || ep[0] != '\\' || ep[1] != 'c')
return NULL;
for (cp = ep; cp > start; cp--)
if (cp[-1] != '\\')
break;
return (ep - cp) % 2 ? NULL : ep;
}
void
man_descope(struct roff_man *man, int line, int offs, char *start)
{
/* Trailing \c keeps next-line scope open. */
if (start != NULL && man_hasc(start) != NULL)
return;
/*
* 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).
* first close out the element scopes (if applicable),
* then close out the block scope (also if applicable).
*/
if (man->flags & MAN_ELINE) {
while (man->last->parent->type != ROFFT_ROOT &&
man_macro(man->last->parent->tok)->flags & MAN_ESCOPED)
man_unscope(man, man->last->parent);
man->flags &= ~MAN_ELINE;
man_unscope(man, man->last->parent);
}
if ( ! (man->flags & MAN_BLINE))
return;
man->flags &= ~MAN_BLINE;
man_unscope(man, man->last->parent);
roff_body_alloc(man, line, offs, man->last->tok);
man->flags &= ~(MAN_BLINE | ROFF_NONOFILL);
}
static int
man_ptext(struct roff_man *man, int line, char *buf, int offs)
{
int i;
const char *cp, *sp;
char *ep;
/* Literal free-form text whitespace is preserved. */
/* In no-fill mode, whitespace is preserved on text lines. */
if (man->flags & MAN_LITERAL) {
if (man->flags & ROFF_NOFILL) {
roff_word_alloc(man, line, offs, buf + offs);
man_descope(man, line, offs);
man_descope(man, line, offs, buf + offs);
return 1;
}
@ -98,26 +122,15 @@ man_ptext(struct roff_man *man, int line, char *buf, int offs)
if (buf[i] == '\0') {
if (man->flags & (MAN_ELINE | MAN_BLINE)) {
mandoc_msg(MANDOCERR_BLK_BLANK, man->parse,
line, 0, NULL);
mandoc_msg(MANDOCERR_BLK_BLANK, line, 0, NULL);
return 1;
}
if (man->last->tok == MAN_SH || man->last->tok == MAN_SS)
return 1;
switch (man->last->type) {
case ROFFT_TEXT:
sp = man->last->string;
cp = ep = strchr(sp, '\0') - 2;
if (cp < sp || cp[0] != '\\' || cp[1] != 'c')
break;
while (cp > sp && cp[-1] == '\\')
cp--;
if ((ep - cp) % 2)
break;
if (man->last->type == ROFFT_TEXT &&
((ep = man_hasc(man->last->string)) != NULL)) {
*ep = '\0';
return 1;
default:
break;
}
roff_elem_alloc(man, line, offs, ROFF_sp);
man->next = ROFF_NEXT_SIBLING;
@ -134,8 +147,7 @@ man_ptext(struct roff_man *man, int line, char *buf, int offs)
if (' ' == buf[i - 1] || '\t' == buf[i - 1]) {
if (i > 1 && '\\' != buf[i - 2])
mandoc_msg(MANDOCERR_SPACE_EOL, man->parse,
line, i - 1, NULL);
mandoc_msg(MANDOCERR_SPACE_EOL, line, i - 1, NULL);
for (--i; i && ' ' == buf[i]; i--)
/* Spin back to non-space. */ ;
@ -157,7 +169,7 @@ man_ptext(struct roff_man *man, int line, char *buf, int offs)
if (mandoc_eos(buf, (size_t)i))
man->last->flags |= NODE_EOS;
man_descope(man, line, offs);
man_descope(man, line, offs, buf + offs);
return 1;
}
@ -180,8 +192,7 @@ man_pmacro(struct roff_man *man, int ln, char *buf, int offs)
if (sz > 0 && sz < 4)
tok = roffhash_find(man->manmac, buf + ppos, sz);
if (tok == TOKEN_NONE) {
mandoc_msg(MANDOCERR_MACRO, man->parse,
ln, ppos, buf + ppos - 1);
mandoc_msg(MANDOCERR_MACRO, ln, ppos, "%s", buf + ppos - 1);
return 1;
}
@ -211,8 +222,7 @@ man_pmacro(struct roff_man *man, int ln, char *buf, int offs)
*/
if (buf[offs] == '\0' && buf[offs - 1] == ' ')
mandoc_msg(MANDOCERR_SPACE_EOL, man->parse,
ln, offs - 1, NULL);
mandoc_msg(MANDOCERR_SPACE_EOL, ln, offs - 1, NULL);
/*
* Some macros break next-line scopes; otherwise, remember
@ -230,16 +240,12 @@ man_pmacro(struct roff_man *man, int ln, char *buf, int offs)
* page, that's very likely what the author intended.
*/
if (bline) {
cp = strchr(buf + offs, '\0') - 2;
if (cp >= buf && cp[0] == '\\' && cp[1] == 'c')
bline = 0;
}
if (bline && man_hasc(buf + offs))
bline = 0;
/* Call to handler... */
assert(man_macros[tok].fp);
(*man_macros[tok].fp)(man, tok, ln, ppos, &offs, buf);
(*man_macro(tok)->fp)(man, tok, ln, ppos, &offs, buf);
/* In quick mode (for mandocdb), abort after the NAME section. */
@ -256,15 +262,15 @@ man_pmacro(struct roff_man *man, int ln, char *buf, int offs)
* unless the next-line scope is allowed to continue.
*/
if ( ! bline || man->flags & MAN_ELINE ||
man_macros[tok].flags & MAN_NSCOPED)
if (bline == 0 ||
(man->flags & MAN_BLINE) == 0 ||
man->flags & MAN_ELINE ||
man_macro(tok)->flags & MAN_NSCOPED)
return 1;
assert(man->flags & MAN_BLINE);
man->flags &= ~MAN_BLINE;
man_unscope(man, man->last->parent);
roff_body_alloc(man, ln, ppos, man->last->tok);
man->flags &= ~(MAN_BLINE | ROFF_NONOFILL);
return 1;
}
@ -280,17 +286,17 @@ man_breakscope(struct roff_man *man, int tok)
*/
if (man->flags & MAN_ELINE && (tok < MAN_TH ||
! (man_macros[tok].flags & MAN_NSCOPED))) {
(man_macro(tok)->flags & MAN_NSCOPED) == 0)) {
n = man->last;
if (n->type == ROFFT_TEXT)
n = n->parent;
if (n->tok < MAN_TH ||
man_macros[n->tok].flags & MAN_NSCOPED)
(man_macro(n->tok)->flags & (MAN_NSCOPED | MAN_ESCOPED))
== MAN_NSCOPED)
n = n->parent;
mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse,
n->line, n->pos, "%s breaks %s",
roff_name[tok], roff_name[n->tok]);
mandoc_msg(MANDOCERR_BLK_LINE, n->line, n->pos,
"%s breaks %s", roff_name[tok], roff_name[n->tok]);
roff_node_delete(man, n);
man->flags &= ~MAN_ELINE;
@ -302,12 +308,12 @@ man_breakscope(struct roff_man *man, int tok)
*/
if (man->flags & MAN_BLINE &&
(tok == MAN_nf || tok == MAN_fi) &&
(tok == ROFF_nf || tok == ROFF_fi) &&
(man->last->tok == MAN_SH || man->last->tok == MAN_SS)) {
n = man->last;
man_unscope(man, n);
roff_body_alloc(man, n->line, n->pos, n->tok);
man->flags &= ~MAN_BLINE;
man->flags &= ~(MAN_BLINE | ROFF_NONOFILL);
}
/*
@ -316,68 +322,24 @@ man_breakscope(struct roff_man *man, int tok)
* Delete the block that is being broken.
*/
if (man->flags & MAN_BLINE && (tok < MAN_TH ||
man_macros[tok].flags & MAN_BSCOPE)) {
if (man->flags & MAN_BLINE && tok != ROFF_nf && tok != ROFF_fi &&
(tok < MAN_TH || man_macro(tok)->flags & MAN_XSCOPE)) {
n = man->last;
if (n->type == ROFFT_TEXT)
n = n->parent;
if (n->tok < MAN_TH ||
(man_macros[n->tok].flags & MAN_BSCOPE) == 0)
(man_macro(n->tok)->flags & MAN_XSCOPE) == 0)
n = n->parent;
assert(n->type == ROFFT_HEAD);
n = n->parent;
assert(n->type == ROFFT_BLOCK);
assert(man_macros[n->tok].flags & MAN_SCOPED);
assert(man_macro(n->tok)->flags & MAN_BSCOPED);
mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse,
n->line, n->pos, "%s breaks %s",
roff_name[tok], roff_name[n->tok]);
mandoc_msg(MANDOCERR_BLK_LINE, n->line, n->pos,
"%s breaks %s", roff_name[tok], roff_name[n->tok]);
roff_node_delete(man, n);
man->flags &= ~MAN_BLINE;
man->flags &= ~(MAN_BLINE | ROFF_NONOFILL);
}
}
const struct mparse *
man_mparse(const struct roff_man *man)
{
assert(man && man->parse);
return man->parse;
}
void
man_state(struct roff_man *man, struct roff_node *n)
{
switch(n->tok) {
case MAN_nf:
case MAN_EX:
if (man->flags & MAN_LITERAL && ! (n->flags & NODE_VALID))
mandoc_msg(MANDOCERR_NF_SKIP, man->parse,
n->line, n->pos, "nf");
man->flags |= MAN_LITERAL;
break;
case MAN_fi:
case MAN_EE:
if ( ! (man->flags & MAN_LITERAL) &&
! (n->flags & NODE_VALID))
mandoc_msg(MANDOCERR_FI_SKIP, man->parse,
n->line, n->pos, "fi");
man->flags &= ~MAN_LITERAL;
break;
default:
break;
}
man->last->flags |= NODE_VALID;
}
void
man_validate(struct roff_man *man)
{
man->last = man->first;
man_node_validate(man);
man->flags &= ~MAN_LITERAL;
}

View File

@ -1,6 +1,6 @@
.\" $Id: man.conf.5,v 1.5 2017/08/22 18:17:52 schwarze Exp $
.\" $Id: man.conf.5,v 1.6 2018/10/02 14:56:47 schwarze Exp $
.\"
.\" Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org>
.\" Copyright (c) 2015, 2017 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
@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: August 22 2017 $
.Dd $Mdocdate: October 2 2018 $
.Dt MAN.CONF 5
.Os
.Sh NAME
@ -98,6 +98,7 @@ manual.
.It Ic man Ta string Ta Cm html Ta path for \&Xr links
.It Ic paper Ta string Ta Cm ps , pdf Ta paper size
.It Ic style Ta string Ta Cm html Ta CSS file
.It Ic toc Ta none Ta Cm html Ta print table of contents
.It Ic width Ta integer Ta Cm ascii , utf8 Ta right margin
.El
.It Ic _whatdb Ar path Ns Cm /whatis.db

View File

@ -1,4 +1,4 @@
/* $Id: man.h,v 1.78 2017/04/24 23:06:18 schwarze Exp $ */
/* $Id: man.h,v 1.79 2018/08/23 19:33:27 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
@ -18,5 +18,4 @@
struct roff_man;
const struct mparse *man_mparse(const struct roff_man *);
void man_validate(struct roff_man *);

View File

@ -1,7 +1,7 @@
/* $Id: man_html.c,v 1.153 2018/07/27 17:49:31 schwarze Exp $ */
/* $Id: man_html.c,v 1.173 2019/03/02 16:30:53 schwarze Exp $ */
/*
* Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013,2014,2015,2017,2018 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2013-2015, 2017-2019 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
@ -33,26 +33,22 @@
#include "html.h"
#include "main.h"
/* FIXME: have PD set the default vspace width. */
#define MAN_ARGS const struct roff_meta *man, \
const struct roff_node *n, \
struct html *h
struct htmlman {
struct man_html_act {
int (*pre)(MAN_ARGS);
int (*post)(MAN_ARGS);
};
static void print_bvspace(struct html *,
const struct roff_node *);
static void print_man_head(const struct roff_meta *,
struct html *);
static void print_man_nodelist(MAN_ARGS);
static void print_man_node(MAN_ARGS);
static int fillmode(struct html *, int);
static char list_continues(const struct roff_node *,
const struct roff_node *);
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);
@ -60,8 +56,9 @@ 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_SY_pre(MAN_ARGS);
static int man_UR_pre(MAN_ARGS);
static int man_abort_pre(MAN_ARGS);
static int man_alt_pre(MAN_ARGS);
static int man_ign_pre(MAN_ARGS);
static int man_in_pre(MAN_ARGS);
@ -70,16 +67,17 @@ static void man_root_post(const struct roff_meta *,
static void man_root_pre(const struct roff_meta *,
struct html *);
static const struct htmlman __mans[MAN_MAX - MAN_TH] = {
static const struct man_html_act man_html_acts[MAN_MAX - MAN_TH] = {
{ NULL, NULL }, /* TH */
{ man_SH_pre, NULL }, /* SH */
{ man_SS_pre, NULL }, /* SS */
{ man_SH_pre, NULL }, /* SS */
{ man_IP_pre, NULL }, /* TP */
{ man_PP_pre, NULL }, /* LP */
{ man_IP_pre, NULL }, /* TQ */
{ man_abort_pre, NULL }, /* LP */
{ man_PP_pre, NULL }, /* PP */
{ man_PP_pre, NULL }, /* P */
{ man_abort_pre, NULL }, /* P */
{ man_IP_pre, NULL }, /* IP */
{ man_HP_pre, NULL }, /* HP */
{ man_PP_pre, NULL }, /* HP */
{ man_SM_pre, NULL }, /* SM */
{ man_SM_pre, NULL }, /* SB */
{ man_alt_pre, NULL }, /* BI */
@ -91,8 +89,6 @@ static const struct htmlman __mans[MAN_MAX - MAN_TH] = {
{ man_I_pre, NULL }, /* I */
{ man_alt_pre, NULL }, /* IR */
{ man_alt_pre, NULL }, /* RI */
{ NULL, NULL }, /* nf */
{ NULL, NULL }, /* fi */
{ NULL, NULL }, /* RE */
{ man_RS_pre, NULL }, /* RS */
{ man_ign_pre, NULL }, /* DT */
@ -100,6 +96,8 @@ static const struct htmlman __mans[MAN_MAX - MAN_TH] = {
{ man_ign_pre, NULL }, /* PD */
{ man_ign_pre, NULL }, /* AT */
{ man_in_pre, NULL }, /* in */
{ man_SY_pre, NULL }, /* SY */
{ NULL, NULL }, /* YS */
{ man_OP_pre, NULL }, /* OP */
{ NULL, NULL }, /* EX */
{ NULL, NULL }, /* EE */
@ -108,34 +106,10 @@ static const struct htmlman __mans[MAN_MAX - MAN_TH] = {
{ man_UR_pre, NULL }, /* MT */
{ NULL, NULL }, /* ME */
};
static const struct htmlman *const mans = __mans - MAN_TH;
/*
* 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 roff_node *n)
{
if (n->body && n->body->child)
if (n->body->child->type == ROFFT_TBL)
return;
if (n->parent->type == ROFFT_ROOT || n->parent->tok != MAN_RS)
if (NULL == n->prev)
return;
print_paragraph(h);
}
void
html_man(void *arg, const struct roff_man *man)
html_man(void *arg, const struct roff_meta *man)
{
struct html *h;
struct roff_node *n;
@ -147,19 +121,19 @@ html_man(void *arg, const struct roff_man *man)
if ((h->oflags & HTML_FRAGMENT) == 0) {
print_gen_decls(h);
print_otag(h, TAG_HTML, "");
if (n->type == ROFFT_COMMENT)
if (n != NULL && n->type == ROFFT_COMMENT)
print_gen_comment(h, n);
t = print_otag(h, TAG_HEAD, "");
print_man_head(&man->meta, h);
print_man_head(man, h);
print_tagq(h, t);
print_otag(h, TAG_BODY, "");
}
man_root_pre(&man->meta, h);
man_root_pre(man, h);
t = print_otag(h, TAG_DIV, "c", "manual-text");
print_man_nodelist(&man->meta, n, h);
print_man_nodelist(man, n, h);
print_tagq(h, t);
man_root_post(&man->meta, h);
man_root_post(man, h);
print_tagq(h, NULL);
}
@ -178,7 +152,6 @@ print_man_head(const struct roff_meta *man, struct html *h)
static void
print_man_nodelist(MAN_ARGS)
{
while (n != NULL) {
print_man_node(man, n, h);
n = n->next;
@ -188,99 +161,33 @@ print_man_nodelist(MAN_ARGS)
static void
print_man_node(MAN_ARGS)
{
static int want_fillmode = MAN_fi;
static int save_fillmode;
struct tag *t;
int child;
/*
* Handle fill mode switch requests up front,
* they would just cause trouble in the subsequent code.
*/
switch (n->tok) {
case MAN_nf:
case MAN_EX:
want_fillmode = MAN_nf;
if (n->type == ROFFT_COMMENT || n->flags & NODE_NOPRT)
return;
case MAN_fi:
case MAN_EE:
want_fillmode = MAN_fi;
if (fillmode(h, 0) == MAN_fi)
print_otag(h, TAG_BR, "");
return;
default:
break;
}
/* Set up fill mode for the upcoming node. */
switch (n->type) {
case ROFFT_BLOCK:
save_fillmode = 0;
/* Some block macros suspend or cancel .nf. */
switch (n->tok) {
case MAN_TP: /* Tagged paragraphs */
case MAN_IP: /* temporarily disable .nf */
case MAN_HP: /* for the head. */
save_fillmode = want_fillmode;
/* FALLTHROUGH */
case MAN_SH: /* Section headers */
case MAN_SS: /* permanently cancel .nf. */
want_fillmode = MAN_fi;
/* FALLTHROUGH */
case MAN_PP: /* These have no head. */
case MAN_LP: /* They will simply */
case MAN_P: /* reopen .nf in the body. */
case MAN_RS:
case MAN_UR:
case MAN_MT:
fillmode(h, MAN_fi);
break;
default:
break;
}
break;
case ROFFT_TBL:
fillmode(h, MAN_fi);
break;
case ROFFT_ELEM:
/*
* Some in-line macros produce tags and/or text
* in the handler, so they require fill mode to be
* configured up front just like for text nodes.
* For the others, keep the traditional approach
* of doing the same, for now.
*/
fillmode(h, want_fillmode);
break;
case ROFFT_TEXT:
if (fillmode(h, want_fillmode) == MAN_fi &&
want_fillmode == MAN_fi &&
n->flags & NODE_LINE && *n->string == ' ' &&
(h->flags & HTML_NONEWLINE) == 0)
print_otag(h, TAG_BR, "");
if (*n->string != '\0')
break;
print_paragraph(h);
return;
case ROFFT_COMMENT:
return;
default:
break;
}
/* Produce output for this node. */
html_fillmode(h, n->flags & NODE_NOFILL ? ROFF_nf : ROFF_fi);
child = 1;
switch (n->type) {
case ROFFT_TEXT:
if (*n->string == '\0') {
print_endline(h);
return;
}
if (*n->string == ' ' && n->flags & NODE_LINE &&
(h->flags & HTML_NONEWLINE) == 0)
print_endline(h);
else if (n->flags & NODE_DELIMC)
h->flags |= HTML_NOSPACE;
t = h->tag;
t->refcnt++;
print_text(h, n->string);
break;
case ROFFT_EQN:
t = h->tag;
t->refcnt++;
print_eqn(h, n->eqn);
break;
case ROFFT_TBL:
@ -306,62 +213,51 @@ print_man_node(MAN_ARGS)
* the "meta" table state. This will be reopened on the
* next table element.
*/
if (h->tblt)
if (h->tblt != NULL)
print_tblclose(h);
t = h->tag;
t->refcnt++;
if (n->tok < ROFF_MAX) {
roff_html_pre(h, n);
child = 0;
break;
t->refcnt--;
print_stagq(h, t);
return;
}
assert(n->tok >= MAN_TH && n->tok < MAN_MAX);
if (mans[n->tok].pre)
child = (*mans[n->tok].pre)(man, n, h);
/* Some block macros resume .nf in the body. */
if (save_fillmode && n->type == ROFFT_BODY)
want_fillmode = save_fillmode;
if (man_html_acts[n->tok - MAN_TH].pre != NULL)
child = (*man_html_acts[n->tok - MAN_TH].pre)(man,
n, h);
break;
}
if (child && n->child)
if (child && n->child != NULL)
print_man_nodelist(man, n->child, h);
/* This will automatically close out any font scope. */
print_stagq(h, t);
if (fillmode(h, 0) == MAN_nf &&
n->next != NULL && n->next->flags & NODE_LINE)
print_endline(h);
}
/*
* MAN_nf switches to no-fill mode, MAN_fi to fill mode.
* Other arguments do not switch.
* The old mode is returned.
*/
static int
fillmode(struct html *h, int want)
{
struct tag *pre;
int had;
for (pre = h->tag; pre != NULL; pre = pre->next)
if (pre->tag == TAG_PRE)
break;
had = pre == NULL ? MAN_fi : MAN_nf;
if (want && want != had) {
if (want == MAN_nf)
print_otag(h, TAG_PRE, "");
else
print_tagq(h, pre);
t->refcnt--;
if (n->type == ROFFT_BLOCK &&
(n->tok == MAN_IP || n->tok == MAN_TP || n->tok == MAN_TQ)) {
t = h->tag;
while (t->tag != TAG_DL && t->tag != TAG_UL)
t = t->next;
/*
* Close the list if no further item of the same type
* follows; otherwise, close the item only.
*/
if (list_continues(n, n->next) == '\0') {
print_tagq(h, t);
t = NULL;
}
}
if (t != NULL)
print_stagq(h, t);
if (n->flags & NODE_NOFILL && n->tok != MAN_YS &&
(n->next != NULL && n->next->flags & NODE_LINE)) {
/* In .nf = <pre>, print even empty lines. */
h->col++;
print_endline(h);
}
return had;
}
static void
@ -382,7 +278,7 @@ man_root_pre(const struct roff_meta *man, struct html *h)
print_stagq(h, tt);
print_otag(h, TAG_TD, "c", "head-vol");
if (NULL != man->vol)
if (man->vol != NULL)
print_text(h, man->vol);
print_stagq(h, tt);
@ -405,7 +301,7 @@ man_root_post(const struct roff_meta *man, struct html *h)
print_stagq(h, tt);
print_otag(h, TAG_TD, "c", "foot-os");
if (man->os)
if (man->os != NULL)
print_text(h, man->os);
print_tagq(h, t);
}
@ -413,13 +309,32 @@ man_root_post(const struct roff_meta *man, struct html *h)
static int
man_SH_pre(MAN_ARGS)
{
char *id;
const char *class;
char *id;
enum htmltag tag;
if (n->type == ROFFT_HEAD) {
if (n->tok == MAN_SH) {
tag = TAG_H1;
class = "Sh";
} else {
tag = TAG_H2;
class = "Ss";
}
switch (n->type) {
case ROFFT_BLOCK:
html_close_paragraph(h);
print_otag(h, TAG_SECTION, "c", class);
break;
case ROFFT_HEAD:
id = html_make_id(n, 1);
print_otag(h, TAG_H1, "cTi", "Sh", id);
print_otag(h, tag, "ci", class, id);
if (id != NULL)
print_otag(h, TAG_A, "chR", "permalink", id);
break;
case ROFFT_BODY:
break;
default:
abort();
}
return 1;
}
@ -428,11 +343,11 @@ static int
man_alt_pre(MAN_ARGS)
{
const struct roff_node *nn;
struct tag *t;
int i;
enum htmltag fp;
struct tag *t;
for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
for (i = 0, nn = n->child; nn != NULL; nn = nn->next, i++) {
switch (n->tok) {
case MAN_BI:
fp = i % 2 ? TAG_I : TAG_B;
@ -474,87 +389,134 @@ static int
man_SM_pre(MAN_ARGS)
{
print_otag(h, TAG_SMALL, "");
if (MAN_SB == n->tok)
if (n->tok == MAN_SB)
print_otag(h, TAG_B, "");
return 1;
}
static int
man_SS_pre(MAN_ARGS)
{
char *id;
if (n->type == ROFFT_HEAD) {
id = html_make_id(n, 1);
print_otag(h, TAG_H2, "cTi", "Ss", id);
if (id != NULL)
print_otag(h, TAG_A, "chR", "permalink", id);
}
return 1;
}
static int
man_PP_pre(MAN_ARGS)
{
if (n->type == ROFFT_HEAD)
switch (n->type) {
case ROFFT_BLOCK:
html_close_paragraph(h);
break;
case ROFFT_HEAD:
return 0;
else if (n->type == ROFFT_BLOCK)
print_bvspace(h, n);
case ROFFT_BODY:
if (n->child != NULL &&
(n->child->flags & NODE_NOFILL) == 0)
print_otag(h, TAG_P, "c",
n->tok == MAN_PP ? "Pp" : "Pp HP");
break;
default:
abort();
}
return 1;
}
static char
list_continues(const struct roff_node *n1, const struct roff_node *n2)
{
const char *s1, *s2;
char c1, c2;
if (n1 == NULL || n1->type != ROFFT_BLOCK ||
n2 == NULL || n2->type != ROFFT_BLOCK)
return '\0';
if ((n1->tok == MAN_TP || n1->tok == MAN_TQ) &&
(n2->tok == MAN_TP || n2->tok == MAN_TQ))
return ' ';
if (n1->tok != MAN_IP || n2->tok != MAN_IP)
return '\0';
n1 = n1->head->child;
n2 = n2->head->child;
s1 = n1 == NULL ? "" : n1->string;
s2 = n2 == NULL ? "" : n2->string;
c1 = strcmp(s1, "*") == 0 ? '*' :
strcmp(s1, "\\-") == 0 ? '-' :
strcmp(s1, "\\(bu") == 0 ? 'b' : ' ';
c2 = strcmp(s2, "*") == 0 ? '*' :
strcmp(s2, "\\-") == 0 ? '-' :
strcmp(s2, "\\(bu") == 0 ? 'b' : ' ';
return c1 != c2 ? '\0' : c1 == 'b' ? '*' : c1;
}
static int
man_IP_pre(MAN_ARGS)
{
const struct roff_node *nn;
const char *list_class;
enum htmltag list_elem, body_elem;
char list_type;
if (n->type == ROFFT_BODY) {
print_otag(h, TAG_DD, "");
nn = n->type == ROFFT_BLOCK ? n : n->parent;
if ((list_type = list_continues(nn->prev, nn)) == '\0') {
/* Start a new list. */
if ((list_type = list_continues(nn, nn->next)) == '\0')
list_type = ' ';
switch (list_type) {
case ' ':
list_class = "Bl-tag";
list_elem = TAG_DL;
break;
case '*':
list_class = "Bl-bullet";
list_elem = TAG_UL;
break;
case '-':
list_class = "Bl-dash";
list_elem = TAG_UL;
break;
default:
abort();
}
} else {
/* Continue a list that was started earlier. */
list_class = NULL;
list_elem = TAG_MAX;
}
body_elem = list_type == ' ' ? TAG_DD : TAG_LI;
switch (n->type) {
case ROFFT_BLOCK:
html_close_paragraph(h);
if (list_elem != TAG_MAX)
print_otag(h, list_elem, "c", list_class);
return 1;
} else if (n->type != ROFFT_HEAD) {
print_otag(h, TAG_DL, "c", "Bl-tag");
case ROFFT_HEAD:
if (body_elem == TAG_LI)
return 0;
print_otag(h, TAG_DT, "");
break;
case ROFFT_BODY:
print_otag(h, body_elem, "");
return 1;
default:
abort();
}
/* FIXME: width specification. */
print_otag(h, TAG_DT, "");
/* For IP, only print the first header element. */
if (MAN_IP == n->tok && n->child)
print_man_node(man, n->child, h);
/* For TP, only print next-line header elements. */
if (MAN_TP == n->tok) {
switch(n->tok) {
case MAN_IP: /* Only print the first header element. */
if (n->child != NULL)
print_man_node(man, n->child, h);
break;
case MAN_TP: /* Only print next-line header elements. */
case MAN_TQ:
nn = n->child;
while (NULL != nn && 0 == (NODE_LINE & nn->flags))
while (nn != NULL && (NODE_LINE & nn->flags) == 0)
nn = nn->next;
while (NULL != nn) {
while (nn != NULL) {
print_man_node(man, nn, h);
nn = nn->next;
}
break;
default:
abort();
}
return 0;
}
static int
man_HP_pre(MAN_ARGS)
{
if (n->type == ROFFT_HEAD)
return 0;
if (n->type == ROFFT_BLOCK) {
print_bvspace(h, n);
print_otag(h, TAG_DIV, "c", "HP");
}
return 1;
}
static int
man_OP_pre(MAN_ARGS)
{
@ -564,14 +526,14 @@ man_OP_pre(MAN_ARGS)
h->flags |= HTML_NOSPACE;
tt = print_otag(h, TAG_SPAN, "c", "Op");
if (NULL != (n = n->child)) {
if ((n = n->child) != NULL) {
print_otag(h, TAG_B, "");
print_text(h, n->string);
}
print_stagq(h, tt);
if (NULL != n && NULL != n->next) {
if (n != NULL && n->next != NULL) {
print_otag(h, TAG_I, "");
print_text(h, n->next->string);
}
@ -606,17 +568,46 @@ man_in_pre(MAN_ARGS)
static int
man_ign_pre(MAN_ARGS)
{
return 0;
}
static int
man_RS_pre(MAN_ARGS)
{
if (n->type == ROFFT_HEAD)
switch (n->type) {
case ROFFT_BLOCK:
html_close_paragraph(h);
break;
case ROFFT_HEAD:
return 0;
if (n->type == ROFFT_BLOCK)
case ROFFT_BODY:
print_otag(h, TAG_DIV, "c", "Bd-indent");
break;
default:
abort();
}
return 1;
}
static int
man_SY_pre(MAN_ARGS)
{
switch (n->type) {
case ROFFT_BLOCK:
html_close_paragraph(h);
print_otag(h, TAG_TABLE, "c", "Nm");
print_otag(h, TAG_TR, "");
break;
case ROFFT_HEAD:
print_otag(h, TAG_TD, "");
print_otag(h, TAG_CODE, "c", "Nm");
break;
case ROFFT_BODY:
print_otag(h, TAG_TD, "");
break;
default:
abort();
}
return 1;
}
@ -624,16 +615,17 @@ static int
man_UR_pre(MAN_ARGS)
{
char *cp;
n = n->child;
assert(n->type == ROFFT_HEAD);
if (n->child != NULL) {
assert(n->child->type == ROFFT_TEXT);
if (n->tok == MAN_MT) {
mandoc_asprintf(&cp, "mailto:%s", n->child->string);
print_otag(h, TAG_A, "cTh", "Mt", cp);
print_otag(h, TAG_A, "ch", "Mt", cp);
free(cp);
} else
print_otag(h, TAG_A, "cTh", "Lk", n->child->string);
print_otag(h, TAG_A, "ch", "Lk", n->child->string);
}
assert(n->next->type == ROFFT_BODY);
@ -641,6 +633,11 @@ man_UR_pre(MAN_ARGS)
n = n->next;
print_man_nodelist(man, n->child, h);
return 0;
}
static int
man_abort_pre(MAN_ARGS)
{
abort();
}

View File

@ -1,7 +1,7 @@
/* $Id: man_macro.c,v 1.123 2017/06/25 11:45:37 schwarze Exp $ */
/* $Id: man_macro.c,v 1.144 2019/01/05 18:59:46 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2012-2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2012-2015, 2017-2019 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2013 Franco Fichtner <franco@lastsummer.de>
*
* Permission to use, copy, modify, and distribute this software for any
@ -22,6 +22,7 @@
#include <assert.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -40,47 +41,54 @@ static int man_args(struct roff_man *, int,
int *, char *, char **);
static void rew_scope(struct roff_man *, enum roff_tok);
const struct man_macro __man_macros[MAN_MAX - MAN_TH] = {
{ 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 }, /* 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 | MAN_JOIN }, /* SM */
{ in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* SB */
static const struct man_macro man_macros[MAN_MAX - MAN_TH] = {
{ in_line_eoln, MAN_XSCOPE }, /* TH */
{ blk_imp, MAN_XSCOPE | MAN_BSCOPED }, /* SH */
{ blk_imp, MAN_XSCOPE | MAN_BSCOPED }, /* SS */
{ blk_imp, MAN_XSCOPE | MAN_BSCOPED }, /* TP */
{ blk_imp, MAN_XSCOPE | MAN_BSCOPED }, /* TQ */
{ blk_imp, MAN_XSCOPE }, /* LP */
{ blk_imp, MAN_XSCOPE }, /* PP */
{ blk_imp, MAN_XSCOPE }, /* P */
{ blk_imp, MAN_XSCOPE }, /* IP */
{ blk_imp, MAN_XSCOPE }, /* HP */
{ in_line_eoln, MAN_NSCOPED | MAN_ESCOPED | MAN_JOIN }, /* SM */
{ in_line_eoln, MAN_NSCOPED | MAN_ESCOPED | MAN_JOIN }, /* 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 | MAN_JOIN }, /* R */
{ in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* B */
{ in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* I */
{ in_line_eoln, MAN_NSCOPED | MAN_ESCOPED | MAN_JOIN }, /* R */
{ in_line_eoln, MAN_NSCOPED | MAN_ESCOPED | MAN_JOIN }, /* B */
{ in_line_eoln, MAN_NSCOPED | MAN_ESCOPED | MAN_JOIN }, /* I */
{ in_line_eoln, 0 }, /* IR */
{ in_line_eoln, 0 }, /* RI */
{ in_line_eoln, MAN_NSCOPED }, /* nf */
{ in_line_eoln, MAN_NSCOPED }, /* fi */
{ blk_close, MAN_BSCOPE }, /* RE */
{ blk_exp, MAN_BSCOPE }, /* RS */
{ blk_close, MAN_XSCOPE }, /* RE */
{ blk_exp, MAN_XSCOPE }, /* RS */
{ in_line_eoln, 0 }, /* DT */
{ in_line_eoln, 0 }, /* UC */
{ in_line_eoln, MAN_NSCOPED }, /* PD */
{ in_line_eoln, 0 }, /* AT */
{ in_line_eoln, MAN_NSCOPED }, /* in */
{ blk_imp, MAN_XSCOPE }, /* SY */
{ blk_close, MAN_XSCOPE }, /* YS */
{ in_line_eoln, 0 }, /* OP */
{ in_line_eoln, MAN_BSCOPE }, /* EX */
{ in_line_eoln, MAN_BSCOPE }, /* EE */
{ blk_exp, MAN_BSCOPE }, /* UR */
{ blk_close, MAN_BSCOPE }, /* UE */
{ blk_exp, MAN_BSCOPE }, /* MT */
{ blk_close, MAN_BSCOPE }, /* ME */
{ in_line_eoln, MAN_XSCOPE }, /* EX */
{ in_line_eoln, MAN_XSCOPE }, /* EE */
{ blk_exp, MAN_XSCOPE }, /* UR */
{ blk_close, MAN_XSCOPE }, /* UE */
{ blk_exp, MAN_XSCOPE }, /* MT */
{ blk_close, MAN_XSCOPE }, /* ME */
};
const struct man_macro *const man_macros = __man_macros - MAN_TH;
const struct man_macro *
man_macro(enum roff_tok tok)
{
assert(tok >= MAN_TH && tok <= MAN_MAX);
return man_macros + (tok - MAN_TH);
}
void
man_unscope(struct roff_man *man, const struct roff_node *to)
{
@ -94,9 +102,10 @@ man_unscope(struct roff_man *man, const struct roff_node *to)
if (to == NULL && ! (n->flags & NODE_VALID)) {
if (man->flags & (MAN_BLINE | MAN_ELINE) &&
man_macros[n->tok].flags & MAN_SCOPED) {
mandoc_vmsg(MANDOCERR_BLK_LINE,
man->parse, n->line, n->pos,
man_macro(n->tok)->flags &
(MAN_BSCOPED | MAN_NSCOPED)) {
mandoc_msg(MANDOCERR_BLK_LINE,
n->line, n->pos,
"EOF breaks %s", roff_name[n->tok]);
if (man->flags & MAN_ELINE)
man->flags &= ~MAN_ELINE;
@ -111,9 +120,9 @@ man_unscope(struct roff_man *man, const struct roff_node *to)
continue;
}
if (n->type == ROFFT_BLOCK &&
man_macros[n->tok].fp == blk_exp)
man_macro(n->tok)->fp == blk_exp)
mandoc_msg(MANDOCERR_BLK_NOEND,
man->parse, n->line, n->pos,
n->line, n->pos, "%s",
roff_name[n->tok]);
}
@ -175,7 +184,7 @@ rew_scope(struct roff_man *man, enum roff_tok tok)
}
if (tok != MAN_SH && (n->tok == MAN_SH ||
(tok != MAN_SS && (n->tok == MAN_SS ||
man_macros[n->tok].fp == blk_exp))))
man_macro(n->tok)->fp == blk_exp))))
return;
man_unscope(man, n);
n = man->last;
@ -189,33 +198,39 @@ rew_scope(struct roff_man *man, enum roff_tok tok)
void
blk_close(MACRO_PROT_ARGS)
{
enum roff_tok ntok;
enum roff_tok ctok, ntok;
const struct roff_node *nn;
char *p;
int nrew, target;
char *p, *ep;
int cline, cpos, la, nrew, target;
nrew = 1;
switch (tok) {
case MAN_RE:
ntok = MAN_RS;
la = *pos;
if ( ! man_args(man, line, pos, buf, &p))
break;
for (nn = man->last->parent; nn; nn = nn->parent)
if (nn->tok == ntok && nn->type == ROFFT_BLOCK)
nrew++;
target = strtol(p, &p, 10);
if (*p != '\0')
mandoc_vmsg(MANDOCERR_ARG_EXCESS, man->parse,
line, p - buf, "RE ... %s", p);
target = strtol(p, &ep, 10);
if (*ep != '\0')
mandoc_msg(MANDOCERR_ARG_EXCESS, line,
la + (buf[la] == '"') + (int)(ep - p),
"RE ... %s", ep);
free(p);
if (target == 0)
target = 1;
nrew -= target;
if (nrew < 1) {
mandoc_vmsg(MANDOCERR_RE_NOTOPEN, man->parse,
mandoc_msg(MANDOCERR_RE_NOTOPEN,
line, ppos, "RE %d", target);
return;
}
break;
case MAN_YS:
ntok = MAN_SY;
break;
case MAN_UE:
ntok = MAN_UR;
break;
@ -231,25 +246,47 @@ blk_close(MACRO_PROT_ARGS)
break;
if (nn == NULL) {
mandoc_msg(MANDOCERR_BLK_NOTOPEN, man->parse,
line, ppos, roff_name[tok]);
mandoc_msg(MANDOCERR_BLK_NOTOPEN,
line, ppos, "%s", roff_name[tok]);
rew_scope(man, MAN_PP);
} else {
line = man->last->line;
ppos = man->last->pos;
ntok = man->last->tok;
man_unscope(man, nn);
if (tok == MAN_RE && nn->head->aux > 0)
roff_setreg(man->roff, "an-margin",
nn->head->aux, '-');
/* Move a trailing paragraph behind the block. */
if (ntok == MAN_LP || ntok == MAN_PP || ntok == MAN_P) {
*pos = strlen(buf);
blk_imp(man, ntok, line, ppos, pos, buf);
if (tok == MAN_RE) {
roff_elem_alloc(man, line, ppos, ROFF_br);
man->last->flags |= NODE_LINE |
NODE_VALID | NODE_ENDED;
man->next = ROFF_NEXT_SIBLING;
}
return;
}
cline = man->last->line;
cpos = man->last->pos;
ctok = man->last->tok;
man_unscope(man, nn);
if (tok == MAN_RE && nn->head->aux > 0)
roff_setreg(man->roff, "an-margin", nn->head->aux, '-');
/* Trailing text. */
if (buf[*pos] != '\0') {
roff_word_alloc(man, line, ppos, buf + *pos);
man->last->flags |= NODE_DELIMC;
if (mandoc_eos(man->last->string, strlen(man->last->string)))
man->last->flags |= NODE_EOS;
}
/* Move a trailing paragraph behind the block. */
if (ctok == MAN_LP || ctok == MAN_PP || ctok == MAN_P) {
*pos = strlen(buf);
blk_imp(man, ctok, cline, cpos, pos, buf);
}
/* Synopsis blocks need an explicit end marker for spacing. */
if (tok == MAN_YS && man->last == nn) {
roff_elem_alloc(man, line, ppos, tok);
man_unscope(man, man->last);
}
}
@ -260,7 +297,10 @@ blk_exp(MACRO_PROT_ARGS)
char *p;
int la;
rew_scope(man, tok);
if (tok == MAN_RS) {
rew_scope(man, tok);
man->flags |= ROFF_NONOFILL;
}
roff_block_alloc(man, line, ppos, tok);
head = roff_head_alloc(man, line, ppos, tok);
@ -275,14 +315,16 @@ blk_exp(MACRO_PROT_ARGS)
roff_setreg(man->roff, "an-margin",
head->aux, '+');
}
free(p);
}
if (buf[*pos] != '\0')
mandoc_vmsg(MANDOCERR_ARG_EXCESS, man->parse, line,
*pos, "%s ... %s", roff_name[tok], buf + *pos);
mandoc_msg(MANDOCERR_ARG_EXCESS, line, *pos,
"%s ... %s", roff_name[tok], buf + *pos);
man_unscope(man, head);
roff_body_alloc(man, line, ppos, tok);
man->flags &= ~ROFF_NONOFILL;
}
/*
@ -299,9 +341,10 @@ blk_imp(MACRO_PROT_ARGS)
struct roff_node *n;
rew_scope(man, tok);
n = roff_block_alloc(man, line, ppos, tok);
if (n->tok == MAN_SH || n->tok == MAN_SS)
man->flags &= ~MAN_LITERAL;
man->flags |= ROFF_NONOFILL;
if (tok == MAN_SH || tok == MAN_SS)
man->flags &= ~ROFF_NOFILL;
roff_block_alloc(man, line, ppos, tok);
n = roff_head_alloc(man, line, ppos, tok);
/* Add line arguments. */
@ -311,16 +354,17 @@ blk_imp(MACRO_PROT_ARGS)
if ( ! man_args(man, line, pos, buf, &p))
break;
roff_word_alloc(man, line, la, p);
free(p);
}
/*
* For macros having optional next-line scope,
* keep the head open if there were no arguments.
* For `TP', always keep the head open.
* For `TP' and `TQ', always keep the head open.
*/
if (man_macros[tok].flags & MAN_SCOPED &&
(tok == MAN_TP || n == man->last)) {
if (man_macro(tok)->flags & MAN_BSCOPED &&
(tok == MAN_TP || tok == MAN_TQ || n == man->last)) {
man->flags |= MAN_BLINE;
return;
}
@ -329,6 +373,7 @@ blk_imp(MACRO_PROT_ARGS)
man_unscope(man, n);
roff_body_alloc(man, line, ppos, tok);
man->flags &= ~ROFF_NONOFILL;
}
void
@ -341,27 +386,26 @@ in_line_eoln(MACRO_PROT_ARGS)
roff_elem_alloc(man, line, ppos, tok);
n = man->last;
if (tok == MAN_EX)
man->flags |= ROFF_NOFILL;
else if (tok == MAN_EE)
man->flags &= ~ROFF_NOFILL;
for (;;) {
if (buf[*pos] != '\0' && (tok == MAN_fi || tok == MAN_nf)) {
mandoc_vmsg(MANDOCERR_ARG_SKIP,
man->parse, line, *pos, "%s %s",
roff_name[tok], buf + *pos);
break;
}
if (buf[*pos] != '\0' && man->last != n && tok == MAN_PD) {
mandoc_vmsg(MANDOCERR_ARG_EXCESS,
man->parse, line, *pos, "%s ... %s",
roff_name[tok], buf + *pos);
mandoc_msg(MANDOCERR_ARG_EXCESS, line, *pos,
"%s ... %s", roff_name[tok], buf + *pos);
break;
}
la = *pos;
if ( ! man_args(man, line, pos, buf, &p))
break;
if (man_macros[tok].flags & MAN_JOIN &&
if (man_macro(tok)->flags & MAN_JOIN &&
man->last->type == ROFFT_TEXT)
roff_word_append(man, p);
else
roff_word_alloc(man, line, la, p);
free(p);
}
/*
@ -374,13 +418,12 @@ in_line_eoln(MACRO_PROT_ARGS)
man->last->flags |= NODE_EOS;
/*
* If no arguments are specified and this is MAN_SCOPED (i.e.,
* If no arguments are specified and this is MAN_ESCOPED (i.e.,
* next-line scoped), then set our mode to indicate that we're
* waiting for terms to load into our context.
*/
if (n == man->last && man_macros[tok].flags & MAN_SCOPED) {
assert( ! (man_macros[tok].flags & MAN_NSCOPED));
if (n == man->last && man_macro(tok)->flags & MAN_ESCOPED) {
man->flags |= MAN_ELINE;
return;
}
@ -391,18 +434,21 @@ in_line_eoln(MACRO_PROT_ARGS)
/* Rewind our element scope. */
for ( ; man->last; man->last = man->last->parent) {
man_state(man, man->last);
man->last->flags |= NODE_VALID;
if (man->last == n)
break;
}
/* Rewind next-line scoped ancestors, if any. */
if (man_macro(tok)->flags & MAN_ESCOPED)
man_descope(man, line, ppos, NULL);
}
void
man_endparse(struct roff_man *man)
{
man_unscope(man, man->first);
man->flags &= ~MAN_LITERAL;
man_unscope(man, man->meta.first);
}
static int
@ -417,6 +463,6 @@ man_args(struct roff_man *man, int line, int *pos, char *buf, char **v)
if ('\0' == *start)
return 0;
*v = mandoc_getarg(man->parse, v, line, pos);
*v = roff_getarg(man->roff, v, line, pos);
return 1;
}

View File

@ -1,7 +1,7 @@
/* $Id: man_term.c,v 1.211 2018/06/10 15:12:35 schwarze Exp $ */
/* $Id: man_term.c,v 1.228 2019/01/05 21:18:26 schwarze Exp $ */
/*
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010-2015, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2010-2015, 2017-2019 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
@ -27,7 +27,6 @@
#include <string.h>
#include "mandoc_aux.h"
#include "mandoc.h"
#include "roff.h"
#include "man.h"
#include "out.h"
@ -37,8 +36,6 @@
#define MAXMARGINS 64 /* maximum number of indented scopes */
struct mtermp {
int fl;
#define MANT_LITERAL (1 << 0)
int lmargin[MAXMARGINS]; /* margins (incl. vis. page) */
int lmargincur; /* index of current margin */
int lmarginsz; /* actual number of nested margins */
@ -51,7 +48,7 @@ struct mtermp {
struct roff_node *n, \
const struct roff_meta *meta
struct termact {
struct man_term_act {
int (*pre)(DECL_ARGS);
void (*post)(DECL_ARGS);
int flags;
@ -78,8 +75,10 @@ static int pre_PP(DECL_ARGS);
static int pre_RS(DECL_ARGS);
static int pre_SH(DECL_ARGS);
static int pre_SS(DECL_ARGS);
static int pre_SY(DECL_ARGS);
static int pre_TP(DECL_ARGS);
static int pre_UR(DECL_ARGS);
static int pre_abort(DECL_ARGS);
static int pre_alternate(DECL_ARGS);
static int pre_ign(DECL_ARGS);
static int pre_in(DECL_ARGS);
@ -89,18 +88,19 @@ static void post_IP(DECL_ARGS);
static void post_HP(DECL_ARGS);
static void post_RS(DECL_ARGS);
static void post_SH(DECL_ARGS);
static void post_SS(DECL_ARGS);
static void post_SY(DECL_ARGS);
static void post_TP(DECL_ARGS);
static void post_UR(DECL_ARGS);
static const struct termact __termacts[MAN_MAX - MAN_TH] = {
static const struct man_term_act man_term_acts[MAN_MAX - MAN_TH] = {
{ NULL, NULL, 0 }, /* TH */
{ pre_SH, post_SH, 0 }, /* SH */
{ pre_SS, post_SS, 0 }, /* SS */
{ pre_SS, post_SH, 0 }, /* SS */
{ pre_TP, post_TP, 0 }, /* TP */
{ pre_PP, NULL, 0 }, /* LP */
{ pre_TP, post_TP, 0 }, /* TQ */
{ pre_abort, NULL, 0 }, /* LP */
{ pre_PP, NULL, 0 }, /* PP */
{ pre_PP, NULL, 0 }, /* P */
{ pre_abort, NULL, 0 }, /* P */
{ pre_IP, post_IP, 0 }, /* IP */
{ pre_HP, post_HP, 0 }, /* HP */
{ NULL, NULL, 0 }, /* SM */
@ -114,8 +114,6 @@ static const struct termact __termacts[MAN_MAX - MAN_TH] = {
{ pre_I, NULL, 0 }, /* I */
{ pre_alternate, NULL, 0 }, /* IR */
{ pre_alternate, NULL, 0 }, /* RI */
{ pre_literal, NULL, 0 }, /* nf */
{ pre_literal, NULL, 0 }, /* fi */
{ NULL, NULL, 0 }, /* RE */
{ pre_RS, post_RS, 0 }, /* RS */
{ pre_DT, NULL, 0 }, /* DT */
@ -123,6 +121,8 @@ static const struct termact __termacts[MAN_MAX - MAN_TH] = {
{ pre_PD, NULL, MAN_NOTEXT }, /* PD */
{ pre_ign, NULL, 0 }, /* AT */
{ pre_in, NULL, MAN_NOTEXT }, /* in */
{ pre_SY, post_SY, 0 }, /* SY */
{ NULL, NULL, 0 }, /* YS */
{ pre_OP, NULL, 0 }, /* OP */
{ pre_literal, NULL, 0 }, /* EX */
{ pre_literal, NULL, 0 }, /* EE */
@ -131,15 +131,22 @@ static const struct termact __termacts[MAN_MAX - MAN_TH] = {
{ pre_UR, post_UR, 0 }, /* MT */
{ NULL, NULL, 0 }, /* ME */
};
static const struct termact *termacts = __termacts - MAN_TH;
static const struct man_term_act *man_term_act(enum roff_tok);
static const struct man_term_act *
man_term_act(enum roff_tok tok)
{
assert(tok >= MAN_TH && tok <= MAN_MAX);
return man_term_acts + (tok - MAN_TH);
}
void
terminal_man(void *arg, const struct roff_man *man)
terminal_man(void *arg, const struct roff_meta *man)
{
struct mtermp mt;
struct termp *p;
struct roff_node *n;
struct mtermp mt;
size_t save_defindent;
p = (struct termp *)arg;
@ -151,7 +158,7 @@ terminal_man(void *arg, const struct roff_man *man)
term_tab_set(p, "T");
term_tab_set(p, ".5i");
memset(&mt, 0, sizeof(struct mtermp));
memset(&mt, 0, sizeof(mt));
mt.lmargin[mt.lmargincur] = term_len(p, p->defindent);
mt.offset = term_len(p, p->defindent);
mt.pardist = 1;
@ -164,18 +171,17 @@ terminal_man(void *arg, const struct roff_man *man)
!strcmp(n->child->child->string, "SYNOPSIS")) {
if (n->child->next->child != NULL)
print_man_nodelist(p, &mt,
n->child->next->child,
&man->meta);
n->child->next->child, man);
term_newln(p);
break;
}
n = n->next;
}
} else {
term_begin(p, print_man_head, print_man_foot, &man->meta);
term_begin(p, print_man_head, print_man_foot, man);
p->flags |= TERMP_NOSPACE;
if (n != NULL)
print_man_nodelist(p, &mt, n, &man->meta);
print_man_nodelist(p, &mt, n, man);
term_end(p);
}
p->defindent = save_defindent;
@ -196,12 +202,12 @@ print_bvspace(struct termp *p, const struct roff_node *n, int pardist)
term_newln(p);
if (n->body && n->body->child)
if (n->body != NULL && n->body->child != NULL)
if (n->body->child->type == ROFFT_TBL)
return;
if (n->parent->type == ROFFT_ROOT || n->parent->tok != MAN_RS)
if (NULL == n->prev)
if (n->prev == NULL)
return;
for (i = 0; i < pardist; i++)
@ -209,17 +215,21 @@ print_bvspace(struct termp *p, const struct roff_node *n, int pardist)
}
static int
pre_abort(DECL_ARGS)
{
abort();
}
static int
pre_ign(DECL_ARGS)
{
return 0;
}
static int
pre_I(DECL_ARGS)
{
term_fontrepl(p, TERMFONT_UNDER);
return 1;
}
@ -227,14 +237,8 @@ pre_I(DECL_ARGS)
static int
pre_literal(DECL_ARGS)
{
term_newln(p);
if (n->tok == MAN_nf || n->tok == MAN_EX)
mt->fl |= MANT_LITERAL;
else
mt->fl &= ~MANT_LITERAL;
/*
* Unlike .IP and .TP, .HP does not have a HEAD.
* So in case a second call to term_flushln() is needed,
@ -247,7 +251,6 @@ pre_literal(DECL_ARGS)
p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
p->flags |= TERMP_NOSPACE;
}
return 0;
}
@ -272,7 +275,7 @@ pre_alternate(DECL_ARGS)
{
enum termfont font[2];
struct roff_node *nn;
int savelit, i;
int i;
switch (n->tok) {
case MAN_RB:
@ -302,29 +305,21 @@ pre_alternate(DECL_ARGS)
default:
abort();
}
savelit = MANT_LITERAL & mt->fl;
mt->fl &= ~MANT_LITERAL;
for (i = 0, nn = n->child; nn; nn = nn->next, i = 1 - i) {
for (i = 0, nn = n->child; nn != NULL; nn = nn->next, i = 1 - i) {
term_fontrepl(p, font[i]);
if (savelit && NULL == nn->next)
mt->fl |= MANT_LITERAL;
assert(nn->type == ROFFT_TEXT);
term_word(p, nn->string);
if (nn->flags & NODE_EOS)
p->flags |= TERMP_SENTENCE;
if (nn->next)
if (nn->next != NULL)
p->flags |= TERMP_NOSPACE;
}
return 0;
}
static int
pre_B(DECL_ARGS)
{
term_fontrepl(p, TERMFONT_BOLD);
return 1;
}
@ -332,20 +327,19 @@ pre_B(DECL_ARGS)
static int
pre_OP(DECL_ARGS)
{
term_word(p, "[");
p->flags |= TERMP_NOSPACE;
p->flags |= TERMP_KEEP | TERMP_NOSPACE;
if (NULL != (n = n->child)) {
if ((n = n->child) != NULL) {
term_fontrepl(p, TERMFONT_BOLD);
term_word(p, n->string);
}
if (NULL != n && NULL != n->next) {
if (n != NULL && n->next != NULL) {
term_fontrepl(p, TERMFONT_UNDER);
term_word(p, n->next->string);
}
term_fontrepl(p, TERMFONT_NONE);
p->flags &= ~TERMP_KEEP;
p->flags |= TERMP_NOSPACE;
term_word(p, "]");
return 0;
@ -369,9 +363,9 @@ pre_in(DECL_ARGS)
cp = n->child->string;
less = 0;
if ('-' == *cp)
if (*cp == '-')
less = -1;
else if ('+' == *cp)
else if (*cp == '+')
less = 1;
else
cp--;
@ -413,13 +407,18 @@ pre_HP(DECL_ARGS)
case ROFFT_BLOCK:
print_bvspace(p, n, mt->pardist);
return 1;
case ROFFT_HEAD:
return 0;
case ROFFT_BODY:
break;
default:
return 0;
abort();
}
if ( ! (MANT_LITERAL & mt->fl)) {
if (n->child == NULL)
return 0;
if ((n->child->flags & NODE_NOFILL) == 0) {
p->flags |= TERMP_NOBREAK | TERMP_BRIND;
p->trailspace = 2;
}
@ -445,8 +444,10 @@ pre_HP(DECL_ARGS)
static void
post_HP(DECL_ARGS)
{
switch (n->type) {
case ROFFT_BLOCK:
case ROFFT_HEAD:
break;
case ROFFT_BODY:
term_newln(p);
@ -466,25 +467,27 @@ post_HP(DECL_ARGS)
p->tcol->rmargin = p->maxrmargin;
break;
default:
break;
abort();
}
}
static int
pre_PP(DECL_ARGS)
{
switch (n->type) {
case ROFFT_BLOCK:
mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
print_bvspace(p, n, mt->pardist);
break;
default:
case ROFFT_HEAD:
return 0;
case ROFFT_BODY:
p->tcol->offset = mt->offset;
break;
default:
abort();
}
return n->type != ROFFT_HEAD;
return 1;
}
static int
@ -492,21 +495,21 @@ pre_IP(DECL_ARGS)
{
struct roffsu su;
const struct roff_node *nn;
int len, savelit;
int len;
switch (n->type) {
case ROFFT_BODY:
p->flags |= TERMP_NOSPACE;
break;
case ROFFT_BLOCK:
print_bvspace(p, n, mt->pardist);
return 1;
case ROFFT_HEAD:
p->flags |= TERMP_NOBREAK;
p->trailspace = 1;
break;
case ROFFT_BLOCK:
print_bvspace(p, n, mt->pardist);
/* FALLTHROUGH */
case ROFFT_BODY:
p->flags |= TERMP_NOSPACE;
break;
default:
return 1;
abort();
}
/* Calculate the offset from the optional second argument. */
@ -526,33 +529,25 @@ pre_IP(DECL_ARGS)
case ROFFT_HEAD:
p->tcol->offset = mt->offset;
p->tcol->rmargin = mt->offset + len;
savelit = MANT_LITERAL & mt->fl;
mt->fl &= ~MANT_LITERAL;
if (n->child)
if (n->child != NULL)
print_man_node(p, mt, n->child, meta);
if (savelit)
mt->fl |= MANT_LITERAL;
return 0;
case ROFFT_BODY:
p->tcol->offset = mt->offset + len;
p->tcol->rmargin = p->maxrmargin;
break;
default:
break;
abort();
}
return 1;
}
static void
post_IP(DECL_ARGS)
{
switch (n->type) {
case ROFFT_BLOCK:
break;
case ROFFT_HEAD:
term_flushln(p);
p->flags &= ~TERMP_NOBREAK;
@ -564,7 +559,7 @@ post_IP(DECL_ARGS)
p->tcol->offset = mt->offset;
break;
default:
break;
abort();
}
}
@ -573,9 +568,13 @@ pre_TP(DECL_ARGS)
{
struct roffsu su;
struct roff_node *nn;
int len, savelit;
int len;
switch (n->type) {
case ROFFT_BLOCK:
if (n->tok == MAN_TP)
print_bvspace(p, n, mt->pardist);
return 1;
case ROFFT_HEAD:
p->flags |= TERMP_NOBREAK | TERMP_BRTRSP;
p->trailspace = 1;
@ -583,11 +582,8 @@ pre_TP(DECL_ARGS)
case ROFFT_BODY:
p->flags |= TERMP_NOSPACE;
break;
case ROFFT_BLOCK:
print_bvspace(p, n, mt->pardist);
/* FALLTHROUGH */
default:
return 1;
abort();
}
/* Calculate offset. */
@ -609,21 +605,15 @@ pre_TP(DECL_ARGS)
p->tcol->offset = mt->offset;
p->tcol->rmargin = mt->offset + len;
savelit = MANT_LITERAL & mt->fl;
mt->fl &= ~MANT_LITERAL;
/* Don't print same-line elements. */
nn = n->child;
while (NULL != nn && 0 == (NODE_LINE & nn->flags))
while (nn != NULL && (nn->flags & NODE_LINE) == 0)
nn = nn->next;
while (NULL != nn) {
while (nn != NULL) {
print_man_node(p, mt, nn, meta);
nn = nn->next;
}
if (savelit)
mt->fl |= MANT_LITERAL;
return 0;
case ROFFT_BODY:
p->tcol->offset = mt->offset + len;
@ -632,17 +622,17 @@ pre_TP(DECL_ARGS)
p->flags &= ~(TERMP_NOBREAK | TERMP_BRTRSP);
break;
default:
break;
abort();
}
return 1;
}
static void
post_TP(DECL_ARGS)
{
switch (n->type) {
case ROFFT_BLOCK:
break;
case ROFFT_HEAD:
term_flushln(p);
break;
@ -651,7 +641,7 @@ post_TP(DECL_ARGS)
p->tcol->offset = mt->offset;
break;
default:
break;
abort();
}
}
@ -662,7 +652,6 @@ pre_SS(DECL_ARGS)
switch (n->type) {
case ROFFT_BLOCK:
mt->fl &= ~MANT_LITERAL;
mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
mt->offset = term_len(p, p->defindent);
@ -674,7 +663,7 @@ pre_SS(DECL_ARGS)
do {
n = n->prev;
} while (n != NULL && n->tok >= MAN_TH &&
termacts[n->tok].flags & MAN_NOTEXT);
man_term_act(n->tok)->flags & MAN_NOTEXT);
if (n == NULL || n->type == ROFFT_COMMENT ||
(n->tok == MAN_SS && n->body->child == NULL))
break;
@ -698,26 +687,9 @@ pre_SS(DECL_ARGS)
default:
break;
}
return 1;
}
static void
post_SS(DECL_ARGS)
{
switch (n->type) {
case ROFFT_HEAD:
term_newln(p);
break;
case ROFFT_BODY:
term_newln(p);
break;
default:
break;
}
}
static int
pre_SH(DECL_ARGS)
{
@ -725,7 +697,6 @@ pre_SH(DECL_ARGS)
switch (n->type) {
case ROFFT_BLOCK:
mt->fl &= ~MANT_LITERAL;
mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
mt->offset = term_len(p, p->defindent);
@ -737,7 +708,7 @@ pre_SH(DECL_ARGS)
do {
n = n->prev;
} while (n != NULL && n->tok >= MAN_TH &&
termacts[n->tok].flags & MAN_NOTEXT);
man_term_act(n->tok)->flags & MAN_NOTEXT);
if (n == NULL || n->type == ROFFT_COMMENT ||
(n->tok == MAN_SH && n->body->child == NULL))
break;
@ -759,25 +730,23 @@ pre_SH(DECL_ARGS)
p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
break;
default:
break;
abort();
}
return 1;
}
static void
post_SH(DECL_ARGS)
{
switch (n->type) {
case ROFFT_HEAD:
term_newln(p);
case ROFFT_BLOCK:
break;
case ROFFT_HEAD:
case ROFFT_BODY:
term_newln(p);
break;
default:
break;
abort();
}
}
@ -792,8 +761,10 @@ pre_RS(DECL_ARGS)
return 1;
case ROFFT_HEAD:
return 0;
default:
case ROFFT_BODY:
break;
default:
abort();
}
n = n->parent->head;
@ -821,42 +792,99 @@ pre_RS(DECL_ARGS)
static void
post_RS(DECL_ARGS)
{
switch (n->type) {
case ROFFT_BLOCK:
return;
case ROFFT_HEAD:
return;
default:
term_newln(p);
case ROFFT_BODY:
break;
default:
abort();
}
term_newln(p);
mt->offset -= n->parent->head->aux;
p->tcol->offset = mt->offset;
if (--mt->lmarginsz < MAXMARGINS)
mt->lmargincur = mt->lmarginsz;
}
static int
pre_SY(DECL_ARGS)
{
const struct roff_node *nn;
int len;
switch (n->type) {
case ROFFT_BLOCK:
if (n->prev == NULL || n->prev->tok != MAN_SY)
print_bvspace(p, n, mt->pardist);
return 1;
case ROFFT_HEAD:
case ROFFT_BODY:
break;
default:
abort();
}
nn = n->parent->head->child;
len = nn == NULL ? 1 : term_strlen(p, nn->string) + 1;
switch (n->type) {
case ROFFT_HEAD:
p->tcol->offset = mt->offset;
p->tcol->rmargin = mt->offset + len;
if (n->next->child == NULL ||
(n->next->child->flags & NODE_NOFILL) == 0)
p->flags |= TERMP_NOBREAK;
term_fontrepl(p, TERMFONT_BOLD);
break;
case ROFFT_BODY:
mt->lmargin[mt->lmargincur] = len;
p->tcol->offset = mt->offset + len;
p->tcol->rmargin = p->maxrmargin;
p->flags |= TERMP_NOSPACE;
break;
default:
abort();
}
return 1;
}
static void
post_SY(DECL_ARGS)
{
switch (n->type) {
case ROFFT_BLOCK:
break;
case ROFFT_HEAD:
term_flushln(p);
p->flags &= ~TERMP_NOBREAK;
break;
case ROFFT_BODY:
term_newln(p);
p->tcol->offset = mt->offset;
break;
default:
abort();
}
}
static int
pre_UR(DECL_ARGS)
{
return n->type != ROFFT_HEAD;
}
static void
post_UR(DECL_ARGS)
{
if (n->type != ROFFT_BLOCK)
return;
term_word(p, "<");
p->flags |= TERMP_NOSPACE;
if (NULL != n->child->child)
if (n->child->child != NULL)
print_man_node(p, mt, n->child->child, meta);
p->flags |= TERMP_NOSPACE;
@ -866,7 +894,8 @@ post_UR(DECL_ARGS)
static void
print_man_node(DECL_ARGS)
{
int c;
const struct man_term_act *act;
int c;
switch (n->type) {
case ROFFT_TEXT:
@ -884,6 +913,8 @@ print_man_node(DECL_ARGS)
} else if (*n->string == ' ' && n->flags & NODE_LINE &&
(p->flags & TERMP_NONEWLINE) == 0)
term_newln(p);
else if (n->flags & NODE_DELIMC)
p->flags |= TERMP_NOSPACE;
term_word(p, n->string);
goto out;
@ -910,20 +941,20 @@ print_man_node(DECL_ARGS)
return;
}
assert(n->tok >= MAN_TH && n->tok <= MAN_MAX);
if ( ! (MAN_NOTEXT & termacts[n->tok].flags))
act = man_term_act(n->tok);
if ((act->flags & MAN_NOTEXT) == 0 && n->tok != MAN_SM)
term_fontrepl(p, TERMFONT_NONE);
c = 1;
if (termacts[n->tok].pre)
c = (*termacts[n->tok].pre)(p, mt, n, meta);
if (act->pre != NULL)
c = (*act->pre)(p, mt, n, meta);
if (c && n->child)
if (c && n->child != NULL)
print_man_nodelist(p, mt, n->child, meta);
if (termacts[n->tok].post)
(*termacts[n->tok].post)(p, mt, n, meta);
if ( ! (MAN_NOTEXT & termacts[n->tok].flags))
if (act->post != NULL)
(*act->post)(p, mt, n, meta);
if ((act->flags & MAN_NOTEXT) == 0 && n->tok != MAN_SM)
term_fontrepl(p, TERMFONT_NONE);
out:
@ -934,7 +965,7 @@ print_man_node(DECL_ARGS)
* -man doesn't have nested macros, we don't need to be
* more specific than this.
*/
if (mt->fl & MANT_LITERAL &&
if (n->flags & NODE_NOFILL &&
! (p->flags & (TERMP_NOBREAK | TERMP_NONEWLINE)) &&
(n->next == NULL || n->next->flags & NODE_LINE)) {
p->flags |= TERMP_BRNEVER | TERMP_NOSPACE;
@ -949,15 +980,13 @@ print_man_node(DECL_ARGS)
p->tcol->rmargin = p->maxrmargin;
}
}
if (NODE_EOS & n->flags)
if (n->flags & NODE_EOS)
p->flags |= TERMP_SENTENCE;
}
static void
print_man_nodelist(DECL_ARGS)
{
while (n != NULL) {
print_man_node(p, mt, n, meta);
n = n->next;
@ -992,7 +1021,7 @@ print_man_foot(struct termp *p, const struct roff_meta *meta)
}
mandoc_asprintf(&title, "%s(%s)",
meta->title, meta->msec);
} else if (meta->os) {
} else if (meta->os != NULL) {
title = mandoc_strdup(meta->os);
} else {
title = mandoc_strdup("");

View File

@ -1,4 +1,4 @@
/* $OpenBSD$ */
/* $Id: man_validate.c,v 1.146 2018/12/31 10:04:39 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010, 2012-2018 Ingo Schwarze <schwarze@openbsd.org>
@ -24,6 +24,7 @@
#include <errno.h>
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
@ -40,28 +41,32 @@
typedef void (*v_check)(CHKARGS);
static void check_abort(CHKARGS);
static void check_par(CHKARGS);
static void check_part(CHKARGS);
static void check_root(CHKARGS);
static void check_text(CHKARGS);
static void post_AT(CHKARGS);
static void post_EE(CHKARGS);
static void post_EX(CHKARGS);
static void post_IP(CHKARGS);
static void post_OP(CHKARGS);
static void post_SH(CHKARGS);
static void post_TH(CHKARGS);
static void post_UC(CHKARGS);
static void post_UR(CHKARGS);
static void post_in(CHKARGS);
static void post_vs(CHKARGS);
static const v_check __man_valids[MAN_MAX - MAN_TH] = {
static const v_check man_valids[MAN_MAX - MAN_TH] = {
post_TH, /* TH */
NULL, /* SH */
NULL, /* SS */
post_SH, /* SH */
post_SH, /* SS */
NULL, /* TP */
check_par, /* LP */
NULL, /* TQ */
check_abort,/* LP */
check_par, /* PP */
check_par, /* P */
check_abort,/* P */
post_IP, /* IP */
NULL, /* HP */
NULL, /* SM */
@ -75,8 +80,6 @@ static const v_check __man_valids[MAN_MAX - MAN_TH] = {
NULL, /* I */
NULL, /* IR */
NULL, /* RI */
NULL, /* nf */
NULL, /* fi */
NULL, /* RE */
check_part, /* RS */
NULL, /* DT */
@ -84,33 +87,56 @@ static const v_check __man_valids[MAN_MAX - MAN_TH] = {
NULL, /* PD */
post_AT, /* AT */
post_in, /* in */
NULL, /* SY */
NULL, /* YS */
post_OP, /* OP */
NULL, /* EX */
NULL, /* EE */
post_EX, /* EX */
post_EE, /* EE */
post_UR, /* UR */
NULL, /* UE */
post_UR, /* MT */
NULL, /* ME */
};
static const v_check *man_valids = __man_valids - MAN_TH;
/* Validate the subtree rooted at man->last. */
void
man_node_validate(struct roff_man *man)
man_validate(struct roff_man *man)
{
struct roff_node *n;
const v_check *cp;
/*
* Translate obsolete macros such that later code
* does not need to look for them.
*/
n = man->last;
switch (n->tok) {
case MAN_LP:
case MAN_P:
n->tok = MAN_PP;
break;
default:
break;
}
/*
* Iterate over all children, recursing into each one
* in turn, depth-first.
*/
man->last = man->last->child;
while (man->last != NULL) {
man_node_validate(man);
man_validate(man);
if (man->last == n)
man->last = man->last->child;
else
man->last = man->last->next;
}
/* Finally validate the macro itself. */
man->last = n;
man->next = ROFF_NEXT_SIBLING;
switch (n->type) {
@ -126,23 +152,15 @@ man_node_validate(struct roff_man *man)
break;
default:
if (n->tok < ROFF_MAX) {
switch (n->tok) {
case ROFF_br:
case ROFF_sp:
post_vs(man, n);
break;
default:
roff_validate(man);
break;
}
roff_validate(man);
break;
}
assert(n->tok >= MAN_TH && n->tok < MAN_MAX);
cp = man_valids + n->tok;
cp = man_valids + (n->tok - MAN_TH);
if (*cp)
(*cp)(man, n);
if (man->last == n)
man_state(man, n);
n->flags |= NODE_VALID;
break;
}
}
@ -153,14 +171,12 @@ check_root(CHKARGS)
assert((man->flags & (MAN_BLINE | MAN_ELINE)) == 0);
if (n->last == NULL || n->last->type == ROFFT_COMMENT)
mandoc_msg(MANDOCERR_DOC_EMPTY, man->parse,
n->line, n->pos, NULL);
mandoc_msg(MANDOCERR_DOC_EMPTY, n->line, n->pos, NULL);
else
man->meta.hasbody = 1;
if (NULL == man->meta.title) {
mandoc_msg(MANDOCERR_TH_NOTITLE, man->parse,
n->line, n->pos, NULL);
mandoc_msg(MANDOCERR_TH_NOTITLE, n->line, n->pos, NULL);
/*
* If a title hasn't been set, do so now (by
@ -175,23 +191,43 @@ check_root(CHKARGS)
if (man->meta.os_e &&
(man->meta.rcsids & (1 << man->meta.os_e)) == 0)
mandoc_msg(MANDOCERR_RCS_MISSING, man->parse, 0, 0,
mandoc_msg(MANDOCERR_RCS_MISSING, 0, 0,
man->meta.os_e == MANDOC_OS_OPENBSD ?
"(OpenBSD)" : "(NetBSD)");
}
static void
check_abort(CHKARGS)
{
abort();
}
static void
check_text(CHKARGS)
{
char *cp, *p;
if (MAN_LITERAL & man->flags)
if (n->flags & NODE_NOFILL)
return;
cp = n->string;
for (p = cp; NULL != (p = strchr(p, '\t')); p++)
mandoc_msg(MANDOCERR_FI_TAB, man->parse,
n->line, n->pos + (p - cp), NULL);
mandoc_msg(MANDOCERR_FI_TAB,
n->line, n->pos + (int)(p - cp), NULL);
}
static void
post_EE(CHKARGS)
{
if ((n->flags & NODE_NOFILL) == 0)
mandoc_msg(MANDOCERR_FI_SKIP, n->line, n->pos, "EE");
}
static void
post_EX(CHKARGS)
{
if (n->flags & NODE_NOFILL)
mandoc_msg(MANDOCERR_NF_SKIP, n->line, n->pos, "EX");
}
static void
@ -199,21 +235,55 @@ post_OP(CHKARGS)
{
if (n->child == NULL)
mandoc_msg(MANDOCERR_OP_EMPTY, man->parse,
n->line, n->pos, "OP");
mandoc_msg(MANDOCERR_OP_EMPTY, n->line, n->pos, "OP");
else if (n->child->next != NULL && n->child->next->next != NULL) {
n = n->child->next->next;
mandoc_vmsg(MANDOCERR_ARG_EXCESS, man->parse,
mandoc_msg(MANDOCERR_ARG_EXCESS,
n->line, n->pos, "OP ... %s", n->string);
}
}
static void
post_SH(CHKARGS)
{
struct roff_node *nc;
if (n->type != ROFFT_BODY || (nc = n->child) == NULL)
return;
if (nc->tok == MAN_PP && nc->body->child != NULL) {
while (nc->body->last != NULL) {
man->next = ROFF_NEXT_CHILD;
roff_node_relink(man, nc->body->last);
man->last = n;
}
}
if (nc->tok == MAN_PP || nc->tok == ROFF_sp || nc->tok == ROFF_br) {
mandoc_msg(MANDOCERR_PAR_SKIP, nc->line, nc->pos,
"%s after %s", roff_name[nc->tok], roff_name[n->tok]);
roff_node_delete(man, nc);
}
/*
* Trailing PP is empty, so it is deleted by check_par().
* Trailing sp is significant.
*/
if ((nc = n->last) != NULL && nc->tok == ROFF_br) {
mandoc_msg(MANDOCERR_PAR_SKIP,
nc->line, nc->pos, "%s at the end of %s",
roff_name[nc->tok], roff_name[n->tok]);
roff_node_delete(man, nc);
}
}
static void
post_UR(CHKARGS)
{
if (n->type == ROFFT_HEAD && n->child == NULL)
mandoc_msg(MANDOCERR_UR_NOHEAD, man->parse,
n->line, n->pos, roff_name[n->tok]);
mandoc_msg(MANDOCERR_UR_NOHEAD, n->line, n->pos,
"%s", roff_name[n->tok]);
check_part(man, n);
}
@ -222,8 +292,8 @@ check_part(CHKARGS)
{
if (n->type == ROFFT_BODY && n->child == NULL)
mandoc_msg(MANDOCERR_BLK_EMPTY, man->parse,
n->line, n->pos, roff_name[n->tok]);
mandoc_msg(MANDOCERR_BLK_EMPTY, n->line, n->pos,
"%s", roff_name[n->tok]);
}
static void
@ -236,15 +306,22 @@ check_par(CHKARGS)
roff_node_delete(man, n);
break;
case ROFFT_BODY:
if (n->child != NULL &&
(n->child->tok == ROFF_sp || n->child->tok == ROFF_br)) {
mandoc_msg(MANDOCERR_PAR_SKIP,
n->child->line, n->child->pos,
"%s after %s", roff_name[n->child->tok],
roff_name[n->tok]);
roff_node_delete(man, n->child);
}
if (n->child == NULL)
mandoc_vmsg(MANDOCERR_PAR_SKIP,
man->parse, n->line, n->pos,
mandoc_msg(MANDOCERR_PAR_SKIP, n->line, n->pos,
"%s empty", roff_name[n->tok]);
break;
case ROFFT_HEAD:
if (n->child != NULL)
mandoc_vmsg(MANDOCERR_ARG_SKIP,
man->parse, n->line, n->pos, "%s %s%s",
mandoc_msg(MANDOCERR_ARG_SKIP,
n->line, n->pos, "%s %s%s",
roff_name[n->tok], n->child->string,
n->child->next != NULL ? " ..." : "");
break;
@ -264,8 +341,7 @@ post_IP(CHKARGS)
break;
case ROFFT_BODY:
if (n->parent->head->child == NULL && n->child == NULL)
mandoc_vmsg(MANDOCERR_PAR_SKIP,
man->parse, n->line, n->pos,
mandoc_msg(MANDOCERR_PAR_SKIP, n->line, n->pos,
"%s empty", roff_name[n->tok]);
break;
default:
@ -298,9 +374,8 @@ post_TH(CHKARGS)
/* Only warn about this once... */
if (isalpha((unsigned char)*p) &&
! isupper((unsigned char)*p)) {
mandoc_vmsg(MANDOCERR_TITLE_CASE,
man->parse, n->line,
n->pos + (p - n->string),
mandoc_msg(MANDOCERR_TITLE_CASE, n->line,
n->pos + (int)(p - n->string),
"TH %s", n->string);
break;
}
@ -308,8 +383,7 @@ post_TH(CHKARGS)
man->meta.title = mandoc_strdup(n->string);
} else {
man->meta.title = mandoc_strdup("");
mandoc_msg(MANDOCERR_TH_NOTITLE, man->parse,
nb->line, nb->pos, "TH");
mandoc_msg(MANDOCERR_TH_NOTITLE, nb->line, nb->pos, "TH");
}
/* TITLE ->MSEC<- DATE OS VOL */
@ -320,7 +394,7 @@ post_TH(CHKARGS)
man->meta.msec = mandoc_strdup(n->string);
else {
man->meta.msec = mandoc_strdup("");
mandoc_vmsg(MANDOCERR_MSEC_MISSING, man->parse,
mandoc_msg(MANDOCERR_MSEC_MISSING,
nb->line, nb->pos, "TH %s", man->meta.title);
}
@ -334,7 +408,7 @@ post_TH(CHKARGS)
mandoc_normdate(man, n->string, n->line, n->pos);
} else {
man->meta.date = mandoc_strdup("");
mandoc_msg(MANDOCERR_DATE_MISSING, man->parse,
mandoc_msg(MANDOCERR_DATE_MISSING,
n ? n->line : nb->line,
n ? n->pos : nb->pos, "TH");
}
@ -362,7 +436,7 @@ post_TH(CHKARGS)
man->meta.vol = mandoc_strdup(p);
if (n != NULL && (n = n->next) != NULL)
mandoc_vmsg(MANDOCERR_ARG_EXCESS, man->parse,
mandoc_msg(MANDOCERR_ARG_EXCESS,
n->line, n->pos, "TH ... %s", n->string);
/*
@ -463,32 +537,3 @@ post_in(CHKARGS)
free(n->child->string);
n->child->string = s;
}
static void
post_vs(CHKARGS)
{
if (NULL != n->prev)
return;
switch (n->parent->tok) {
case MAN_SH:
case MAN_SS:
case MAN_PP:
case MAN_LP:
case MAN_P:
mandoc_vmsg(MANDOCERR_PAR_SKIP, man->parse, n->line, n->pos,
"%s after %s", roff_name[n->tok],
roff_name[n->parent->tok]);
/* FALLTHROUGH */
case TOKEN_NONE:
/*
* Don't warn about this because it occurs in pod2man
* and would cause considerable (unfixable) warnage.
*/
roff_node_delete(man, n);
break;
default:
break;
}
}

View File

@ -1,6 +1,6 @@
/* $Id: manconf.h,v 1.5 2017/07/01 09:47:30 schwarze Exp $ */
/* $Id: manconf.h,v 1.7 2018/11/22 11:30:23 schwarze Exp $ */
/*
* Copyright (c) 2011, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2011, 2015, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
@ -30,12 +30,14 @@ struct manoutput {
char *man;
char *paper;
char *style;
char *tag;
size_t indent;
size_t width;
int fragment;
int mdoc;
int synopsisonly;
int noval;
int synopsisonly;
int toc;
};
struct manconf {

View File

@ -1,4 +1,4 @@
.\" $Id: mandoc.1,v 1.226 2018/07/28 18:34:15 schwarze Exp $
.\" $Id: mandoc.1,v 1.237 2019/02/23 18:53:54 schwarze Exp $
.\"
.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
.\" Copyright (c) 2012, 2014-2018 Ingo Schwarze <schwarze@openbsd.org>
@ -15,7 +15,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: July 28 2018 $
.Dd $Mdocdate: February 23 2019 $
.Dt MANDOC 1
.Os
.Sh NAME
@ -256,10 +256,28 @@ where
is the back-space character number 8.
Emboldened characters are rendered as
.Sq c Ns \e[bs] Ns c .
This markup is typically converted to appropriate terminal sequences by
the pager or
.Xr ul 1 .
To remove the markup, pipe the output to
.Xr col 1
.Fl b
instead.
.Pp
The special characters documented in
.Xr mandoc_char 7
are rendered best-effort in an ASCII equivalent.
In particular, opening and closing
.Sq single quotes
are represented as characters number 0x60 and 0x27, respectively,
which agrees with all ASCII standards from 1965 to the latest
revision (2012) and which matches the traditional way in which
.Xr roff 7
formatters represent single quotes in ASCII output.
This correct ASCII rendering may look strange with modern
Unicode-compatible fonts because contrary to ASCII, Unicode uses
the code point U+0060 for the grave accent only, never for an opening
quote.
.Pp
The following
.Fl O
@ -290,6 +308,26 @@ One useful application is for checking that
output formats in the same way as the
.Xr mdoc 7
source it was generated from.
.It Cm tag Ns Op = Ns Ar term
If the formatted manual page is opened in a pager,
go to the definition of the
.Ar term
rather than showing the manual page from the beginning.
If no
.Ar term
is specified, reuse the first command line argument that is not a
.Ar section
number.
If that argument is in
.Xr apropos 1
.Ar key Ns = Ns Ar val
format, only the
.Ar val
is used rather than the argument as a whole.
This is useful for commands like
.Ql man -akO tag Ic=ulimit
to search for a keyword and jump right to its definition
in the matching manual pages.
.It Cm width Ns = Ns Ar width
The output width is set to
.Ar width
@ -308,9 +346,9 @@ Equations rendered from
.Xr eqn 7
blocks use MathML.
.Pp
The
.Pa mandoc.css
file documents style-sheet classes available for customising output.
The file
.Pa /usr/share/misc/mandoc.css
documents style-sheet classes available for customising output.
If a style-sheet is not specified with
.Fl O Cm style ,
.Fl T Cm html
@ -345,7 +383,7 @@ Instances of
are replaced with the include filename.
The default is not to present a
hyperlink.
.It Cm man Ns = Ns Ar fmt
.It Cm man Ns = Ns Ar fmt Ns Op ; Ns Ar fmt
The string
.Ar fmt ,
for example,
@ -361,12 +399,19 @@ 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.
If two formats are given and a file
.Ar %N.%S
exists in the current directory, the first format is used;
otherwise, the second format is used.
.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.
.It Cm toc
If an input file contains at least two non-standard sections,
print a table of contents near the beginning of the output.
.El
.Ss Locale Output
By default,
@ -667,10 +712,10 @@ To page manuals to the terminal:
.Dl $ mandoc -l mandoc.1 man.1 apropos.1 makewhatis.8
.Pp
To produce HTML manuals with
.Pa mandoc.css
.Pa /usr/share/misc/mandoc.css
as the style-sheet:
.Pp
.Dl $ mandoc \-T html -O style=mandoc.css mdoc.7 \*(Gt mdoc.7.html
.Dl $ mandoc \-T html -O style=/usr/share/misc/mandoc.css mdoc.7 > mdoc.7.html
.Pp
To check over a large set of manuals:
.Pp
@ -678,7 +723,7 @@ To check over a large set of manuals:
.Pp
To produce a series of PostScript manuals for A4 paper:
.Pp
.Dl $ mandoc \-T ps \-O paper=a4 mdoc.7 man.7 \*(Gt manuals.ps
.Dl $ mandoc \-T ps \-O paper=a4 mdoc.7 man.7 > manuals.ps
.Pp
Convert a modern
.Xr mdoc 7
@ -688,20 +733,36 @@ format, for use on systems lacking an
.Xr mdoc 7
parser:
.Pp
.Dl $ mandoc \-T man foo.mdoc \*(Gt foo.man
.Dl $ mandoc \-T man foo.mdoc > foo.man
.Sh DIAGNOSTICS
Messages displayed by
.Nm
follow this format:
.Bd -ragged -offset indent
.Nm :
.Ar file : Ns Ar line : Ns Ar column : level : message : macro args
.Ar file : Ns Ar line : Ns Ar column : level : message : macro arguments
.Pq Ar os
.Ed
.Pp
Line and column numbers start at 1.
The first three fields identify the
.Ar file
name,
.Ar line
number, and
.Ar column
number of the input file where the message was triggered.
The line and column numbers start at 1.
Both are omitted for messages referring to an input file as a whole.
Macro names and arguments are omitted where meaningless.
All
.Ar level
and
.Ar message
strings are explained below.
The name of the
.Ar macro
triggering the message and its
.Ar arguments
are omitted where meaningless.
The
.Ar os
operating system specifier is omitted for messages that are relevant
@ -1606,6 +1667,12 @@ or
.Cm off .
The invalid argument is moved out of the macro, which leaves the macro
empty, causing it to toggle the spacing mode.
.It Sy "argument contains two font escapes"
.Pq roff
The second argument of a
.Ic char
request contains more than one font escape sequence.
A wrong font may remain active after using the character.
.It Sy "unknown font, skipping request"
.Pq man , tbl
A
@ -1651,7 +1718,8 @@ Start it on a new input line to help formatters produce correct spacing.
.It Sy "invalid escape sequence"
.Pq roff
An escape sequence has an invalid opening argument delimiter, lacks the
closing argument delimiter, or the argument has too few characters.
closing argument delimiter, the argument is of an invalid form, or it is
a character escape sequence with an invalid name.
If the argument is incomplete,
.Ic \e*
and
@ -1664,6 +1732,12 @@ and
.Ic \ew
to the length of the incomplete argument.
All other invalid escape sequences are ignored.
.It Sy "undefined escape, printing literally"
.Pq roff
In an escape sequence, the first character
right after the leading backslash is invalid.
That character is printed literally,
which is equivalent to ignoring the backslash.
.It Sy "undefined string, using \(dq\(dq"
.Pq roff
If a string is used without being defined before,
@ -1807,6 +1881,13 @@ or
macro.
It may be mistyped or unsupported.
The request or macro is discarded including its arguments.
.It Sy "skipping request outside macro"
.Pq roff
A
.Ic shift
or
.Ic return
request occurs outside any macro definition and has no effect.
.It Sy "skipping insecure request"
.Pq roff
An input file attempted to run a shell command
@ -1916,6 +1997,14 @@ When parsing for a request or a user-defined macro name to be called,
only the escape sequence is discarded.
The characters preceding it are used as the request or macro name,
the characters following it are used as the arguments to the request or macro.
.It Sy "using macro argument outside macro"
.Pq roff
The escape sequence \e$ occurs outside any macro definition
and expands to the empty string.
.It Sy "argument number is not numeric"
.Pq roff
The argument of the escape sequence \e$ is not a digit;
the escape sequence expands to the empty string.
.It Sy "NOT IMPLEMENTED: Bd -file"
.Pq mdoc
For security reasons, the
@ -1944,6 +2033,13 @@ macro fails to specify the list type.
The argument of a
.Ic \&ce
request is not a number.
.It Sy "argument is not a character"
.Pq roff
The first argument of a
.Ic char
request is neither a single ASCII character
nor a single character escape sequence.
The request is ignored including all its arguments.
.It Sy "missing manual name, using \(dq\(dq"
.Pq mdoc
The first call to
@ -1978,6 +2074,13 @@ or
.Ic \&gsize
statement has a non-numeric or negative argument or no argument at all.
The invalid request or statement is ignored.
.It Sy "excessive shift"
.Pq roff
The argument of a
.Ic shift
request is larger than the number of arguments of the macro that is
currently being executed.
All macro arguments are deleted and \en(.$ is set to zero.
.It Sy "NOT IMPLEMENTED: .so with absolute path or \(dq..\(dq"
.Pq roff
For security reasons,
@ -2100,6 +2203,13 @@ implementations but not by
.Nm
was found in an input file.
It is replaced by a question mark.
.It Sy "unsupported escape sequence"
.Pq roff
An input file contains an escape sequence supported by GNU troff
or Heirloom troff but not by
.Nm ,
and it is likely that this will cause information loss
or considerable misformatting.
.It Sy "unsupported roff request"
.Pq roff
An input file contains a

View File

@ -1,4 +1,4 @@
.\" $Id: mandoc.3,v 1.41 2017/07/04 23:40:01 schwarze Exp $
.\" $Id: mandoc.3,v 1.44 2018/12/30 00:49:55 schwarze Exp $
.\"
.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
.\" Copyright (c) 2010-2017 Ingo Schwarze <schwarze@openbsd.org>
@ -15,30 +15,23 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: July 4 2017 $
.Dd $Mdocdate: December 30 2018 $
.Dt MANDOC 3
.Os
.Sh NAME
.Nm mandoc ,
.Nm deroff ,
.Nm mandocmsg ,
.Nm man_mparse ,
.Nm man_validate ,
.Nm mdoc_validate ,
.Nm mparse_alloc ,
.Nm mparse_copy ,
.Nm mparse_free ,
.Nm mparse_getkeep ,
.Nm mparse_keep ,
.Nm mparse_open ,
.Nm mparse_readfd ,
.Nm mparse_reset ,
.Nm mparse_result ,
.Nm mparse_strerror ,
.Nm mparse_strlevel ,
.Nm mparse_updaterc
.Nm mparse_result
.Nd mandoc macro compiler library
.Sh SYNOPSIS
.In sys/types.h
.In stdio.h
.In mandoc.h
.Pp
.Fd "#define ASCII_NBRSP"
@ -47,38 +40,23 @@
.Ft struct mparse *
.Fo mparse_alloc
.Fa "int options"
.Fa "enum mandocerr mmin"
.Fa "mandocmsg mmsg"
.Fa "enum mandoc_os oe_e"
.Fa "char *os_s"
.Fc
.Ft void
.Fo (*mandocmsg)
.Fa "enum mandocerr errtype"
.Fa "enum mandoclevel level"
.Fa "const char *file"
.Fa "int line"
.Fa "int col"
.Fa "const char *msg"
.Fc
.Ft void
.Fo mparse_free
.Fa "struct mparse *parse"
.Fc
.Ft const char *
.Fo mparse_getkeep
.Fa "const struct mparse *parse"
.Fc
.Ft void
.Fo mparse_keep
.Fa "struct mparse *parse"
.Fo mparse_copy
.Fa "const struct mparse *parse"
.Fc
.Ft int
.Fo mparse_open
.Fa "struct mparse *parse"
.Fa "const char *fname"
.Fc
.Ft "enum mandoclevel"
.Ft void
.Fo mparse_readfd
.Fa "struct mparse *parse"
.Fa "int fd"
@ -88,24 +66,9 @@
.Fo mparse_reset
.Fa "struct mparse *parse"
.Fc
.Ft void
.Ft struct roff_meta *
.Fo mparse_result
.Fa "struct mparse *parse"
.Fa "struct roff_man **man"
.Fa "char **sodest"
.Fc
.Ft "const char *"
.Fo mparse_strerror
.Fa "enum mandocerr"
.Fc
.Ft "const char *"
.Fo mparse_strlevel
.Fa "enum mandoclevel"
.Fc
.Ft void
.Fo mparse_updaterc
.Fa "struct mparse *parse"
.Fa "enum mandoclevel *rc"
.Fc
.In roff.h
.Ft void
@ -118,22 +81,10 @@
.In mdoc.h
.Vt extern const char * const * mdoc_argnames;
.Vt extern const char * const * mdoc_macronames;
.Ft void
.Fo mdoc_validate
.Fa "struct roff_man *mdoc"
.Fc
.In sys/types.h
.In mandoc.h
.In man.h
.Vt extern const char * const * man_macronames;
.Ft "const struct mparse *"
.Fo man_mparse
.Fa "const struct roff_man *man"
.Fc
.Ft void
.Fo man_validate
.Fa "struct roff_man *man"
.Fc
.Sh DESCRIPTION
The
.Nm mandoc
@ -174,27 +125,13 @@ close it with
retrieve the syntax tree with
.Fn mparse_result ;
.It
depending on whether the
.Fa macroset
member of the returned
.Vt struct roff_man
is
.Dv MACROSET_MDOC
or
.Dv MACROSET_MAN ,
validate it with
.Fn mdoc_validate
or
.Fn man_validate ,
respectively;
.It
if information about the validity of the input is needed, fetch it with
.Fn mparse_updaterc ;
.It
iterate over parse nodes with starting from the
.Fa first
member of the returned
.Vt struct roff_man ;
.Vt struct roff_meta ;
.It
free all allocated memory with
.Fn mparse_free
@ -232,9 +169,6 @@ and freed with
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 error and warning
messages emitted by the parser.
.El
.Ss Functions
.Bl -ohang
@ -245,35 +179,11 @@ including text contained in its child nodes.
To be used on children of the
.Fa first
member of
.Vt struct roff_man .
.Vt struct roff_meta .
When it is no longer needed, the pointer returned from
.Fn deroff
can be passed to
.Xr free 3 .
.It Fn man_mparse
Get the parser used for the current output.
Declared in
.In man.h ,
implemented in
.Pa man.c .
.It Fn man_validate
Validate the
.Dv MACROSET_MAN
parse tree obtained with
.Fn mparse_result .
Declared in
.In man.h ,
implemented in
.Pa man.c .
.It Fn mdoc_validate
Validate the
.Dv MACROSET_MDOC
parse tree obtained with
.Fn mparse_result .
Declared in
.In mdoc.h ,
implemented in
.Pa mdoc.c .
.It Fn mparse_alloc
Allocate a parser.
The arguments have the following effect:
@ -295,8 +205,8 @@ file inclusion requests are always honoured.
Otherwise, if the request is the only content in an input file,
only the file name is remembered, to be returned in the
.Fa sodest
argument of
.Fn mparse_result .
field of
.Vt struct roff_meta .
.Pp
When the
.Dv MPARSE_QUICK
@ -305,24 +215,14 @@ This is for example useful in
.Xr makewhatis 8
.Fl Q
to quickly build minimal databases.
.It Ar mmin
Can be set to
.Dv MANDOCERR_BASE ,
.Dv MANDOCERR_STYLE ,
.Dv MANDOCERR_WARNING ,
.Dv MANDOCERR_ERROR ,
.Dv MANDOCERR_UNSUPP ,
or
.Dv MANDOCERR_MAX .
Messages below the selected level will be suppressed.
.It Ar mmsg
A callback function to handle errors and warnings.
See
.Pa main.c
for an example.
If printing of error messages is not desired,
.Dv NULL
may be passed.
.Pp
When the
.Dv MARSE_VALIDATE
bit is set,
.Fn mparse_result
runs the validation functions before returning the syntax tree.
This is almost always required, except in certain debugging scenarios,
for example to dump unvalidated syntax trees.
.It Ar os_e
Operating system to check base system conventions for.
If
@ -361,19 +261,9 @@ Declared in
.In mandoc.h ,
implemented in
.Pa read.c .
.It Fn mparse_getkeep
Acquire the keep buffer.
Must follow a call of
.Fn mparse_keep .
Declared in
.In mandoc.h ,
implemented in
.Pa read.c .
.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_copy
Dump a copy of the input to the standard output; used for
.Fl man T Ns Cm man .
Declared in
.In mandoc.h ,
implemented in
@ -421,35 +311,6 @@ implemented in
.Pa read.c .
.It Fn mparse_result
Obtain the result of a parse.
One of the two pointers will be filled in.
Declared in
.In mandoc.h ,
implemented in
.Pa read.c .
.It Fn mparse_strerror
Return a statically-allocated string representation of an error code.
Declared in
.In mandoc.h ,
implemented in
.Pa read.c .
.It Fn mparse_strlevel
Return a statically-allocated string representation of a level code.
Declared in
.In mandoc.h ,
implemented in
.Pa read.c .
.It Fn mparse_updaterc
If the highest warning or error level that occurred during the current
.Fa parse
is higher than
.Pf * Fa rc ,
update
.Pf * Fa rc
accordingly.
This is useful after calling
.Fn mdoc_validate
or
.Fn man_validate .
Declared in
.In mandoc.h ,
implemented in

View File

@ -1,4 +1,4 @@
/* $Id: mandoc.c,v 1.104 2018/07/28 18:34:15 schwarze Exp $ */
/* $Id: mandoc.c,v 1.114 2018/12/30 00:49:55 schwarze Exp $ */
/*
* Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011-2015, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
@ -32,16 +32,70 @@
#include "mandoc.h"
#include "roff.h"
#include "libmandoc.h"
#include "roff_int.h"
static int a2time(time_t *, const char *, const char *);
static char *time2a(time_t);
enum mandoc_esc
mandoc_font(const char *cp, int sz)
{
switch (sz) {
case 0:
return ESCAPE_FONTPREV;
case 1:
switch (cp[0]) {
case 'B':
case '3':
return ESCAPE_FONTBOLD;
case 'I':
case '2':
return ESCAPE_FONTITALIC;
case 'P':
return ESCAPE_FONTPREV;
case 'R':
case '1':
return ESCAPE_FONTROMAN;
case '4':
return ESCAPE_FONTBI;
default:
return ESCAPE_ERROR;
}
case 2:
switch (cp[0]) {
case 'B':
switch (cp[1]) {
case 'I':
return ESCAPE_FONTBI;
default:
return ESCAPE_ERROR;
}
case 'C':
switch (cp[1]) {
case 'B':
return ESCAPE_FONTBOLD;
case 'I':
return ESCAPE_FONTITALIC;
case 'R':
case 'W':
return ESCAPE_FONTCW;
default:
return ESCAPE_ERROR;
}
default:
return ESCAPE_ERROR;
}
default:
return ESCAPE_ERROR;
}
}
enum mandoc_esc
mandoc_escape(const char **end, const char **start, int *sz)
{
const char *local_start;
int local_sz;
int local_sz, c, i;
char term;
enum mandoc_esc gly;
@ -55,6 +109,14 @@ mandoc_escape(const char **end, const char **start, int *sz)
if (NULL == sz)
sz = &local_sz;
/*
* Treat "\E" just like "\";
* it only makes a difference in copy mode.
*/
if (**end == 'E')
++*end;
/*
* Beyond the backslash, at least one input character
* is part of the escape sequence. With one exception
@ -77,6 +139,10 @@ mandoc_escape(const char **end, const char **start, int *sz)
*sz = 2;
break;
case '[':
if (**start == ' ') {
++*end;
return ESCAPE_ERROR;
}
gly = ESCAPE_SPECIAL;
term = ']';
break;
@ -91,11 +157,26 @@ mandoc_escape(const char **end, const char **start, int *sz)
/*
* Escapes taking no arguments at all.
*/
case 'd':
case 'u':
case '!':
case '?':
return ESCAPE_UNSUPP;
case '%':
case '&':
case ')':
case ',':
case '/':
case '^':
case 'a':
case 'd':
case 'r':
case 't':
case 'u':
case '{':
case '|':
case '}':
return ESCAPE_IGNORE;
case 'c':
return ESCAPE_NOSPACE;
case 'p':
return ESCAPE_BREAK;
@ -113,32 +194,57 @@ mandoc_escape(const char **end, const char **start, int *sz)
* 'X' is the trigger. These have opaque sub-strings.
*/
case 'F':
case 'f':
case 'g':
case 'k':
case 'M':
case 'm':
case 'n':
case 'O':
case 'V':
case 'Y':
gly = ESCAPE_IGNORE;
/* FALLTHROUGH */
case 'f':
if (ESCAPE_ERROR == gly)
gly = ESCAPE_FONT;
gly = (*start)[-1] == 'f' ? ESCAPE_FONT : ESCAPE_IGNORE;
switch (**start) {
case '(':
if ((*start)[-1] == 'O')
gly = ESCAPE_ERROR;
*start = ++*end;
*sz = 2;
break;
case '[':
if ((*start)[-1] == 'O')
gly = (*start)[1] == '5' ?
ESCAPE_UNSUPP : ESCAPE_ERROR;
*start = ++*end;
term = ']';
break;
default:
if ((*start)[-1] == 'O') {
switch (**start) {
case '0':
gly = ESCAPE_UNSUPP;
break;
case '1':
case '2':
case '3':
case '4':
break;
default:
gly = ESCAPE_ERROR;
break;
}
}
*sz = 1;
break;
}
break;
case '*':
if (strncmp(*start, "(.T", 3) != 0)
abort();
gly = ESCAPE_DEVICE;
*start = ++*end;
*sz = 2;
break;
/*
* These escapes are of the form \X'Y', where 'X' is the trigger
@ -250,18 +356,29 @@ mandoc_escape(const char **end, const char **start, int *sz)
break;
/*
* Anything else is assumed to be a glyph.
* In this case, pass back the character after the backslash.
* Several special characters can be encoded as
* one-byte escape sequences without using \[].
*/
default:
case ' ':
case '\'':
case '-':
case '.':
case '0':
case ':':
case '_':
case '`':
case 'e':
case '~':
gly = ESCAPE_SPECIAL;
/* FALLTHROUGH */
default:
if (gly == ESCAPE_ERROR)
gly = ESCAPE_UNDEF;
*start = --*end;
*sz = 1;
break;
}
assert(ESCAPE_ERROR != gly);
/*
* Read up to the terminating character,
* paying attention to nested escapes.
@ -284,6 +401,15 @@ mandoc_escape(const char **end, const char **start, int *sz)
}
}
*sz = (*end)++ - *start;
/*
* The file chars.c only provides one common list
* of character names, but \[-] == \- is the only
* one of the characters with one-byte names that
* allows enclosing the name in brackets.
*/
if (gly == ESCAPE_SPECIAL && *sz == 1 && **start != '-')
return ESCAPE_ERROR;
} else {
assert(*sz > 0);
if ((size_t)*sz > strlen(*start))
@ -295,43 +421,25 @@ mandoc_escape(const char **end, const char **start, int *sz)
switch (gly) {
case ESCAPE_FONT:
if (2 == *sz) {
if ('C' == **start) {
/*
* Treat constant-width font modes
* just like regular font modes.
*/
(*start)++;
(*sz)--;
} else {
if ('B' == (*start)[0] && 'I' == (*start)[1])
gly = ESCAPE_FONTBI;
break;
}
} else if (1 != *sz)
break;
switch (**start) {
case '3':
case 'B':
gly = ESCAPE_FONTBOLD;
break;
case '2':
case 'I':
gly = ESCAPE_FONTITALIC;
break;
case 'P':
gly = ESCAPE_FONTPREV;
break;
case '1':
case 'R':
gly = ESCAPE_FONTROMAN;
break;
}
gly = mandoc_font(*start, *sz);
break;
case ESCAPE_SPECIAL:
if (1 == *sz && 'c' == **start)
gly = ESCAPE_NOSPACE;
if (**start == 'c') {
if (*sz < 6 || *sz > 7 ||
strncmp(*start, "char", 4) != 0 ||
(int)strspn(*start + 4, "0123456789") + 4 < *sz)
break;
c = 0;
for (i = 4; i < *sz; i++)
c = 10 * c + ((*start)[i] - '0');
if (c < 0x21 || (c > 0x7e && c < 0xa0) || c > 0xff)
break;
*start += 4;
*sz -= 4;
gly = ESCAPE_NUMBERED;
break;
}
/*
* Unicode escapes are defined in groff as \[u0000]
* to \[u10FFFF], where the contained value must be
@ -358,101 +466,6 @@ mandoc_escape(const char **end, const char **start, int *sz)
return gly;
}
/*
* 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.
* NUL-terminate the argument in place.
* Collapse pairs of quotes inside quoted arguments.
* Advance the argument pointer to the next argument,
* or to the NUL 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 the following text left
* after quoted quotes and after "\\" and "\t".
*/
if (pairs)
cp[-pairs] = cp[0];
if ('\\' == cp[0]) {
/*
* In copy mode, translate double to single
* backslashes and backslash-t to literal tabs.
*/
switch (cp[1]) {
case 't':
cp[0] = '\t';
/* FALLTHROUGH */
case '\\':
pairs++;
cp++;
break;
case ' ':
/* Skip escaped blanks. */
if (0 == quoted)
cp++;
break;
default:
break;
}
} 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_ARG_QUOTE, parse, ln, *pos, NULL);
/* NUL-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_SPACE_EOL, parse, ln, *pos, NULL);
return start;
}
static int
a2time(time_t *t, const char *fmt, const char *p)
{
@ -529,7 +542,7 @@ mandoc_normdate(struct roff_man *man, char *in, int ln, int pos)
/* No date specified: use today's date. */
if (in == NULL || *in == '\0' || strcmp(in, "$" "Mdocdate$") == 0) {
mandoc_msg(MANDOCERR_DATE_MISSING, man->parse, ln, pos, NULL);
mandoc_msg(MANDOCERR_DATE_MISSING, ln, pos, NULL);
return time2a(time(NULL));
}
@ -539,23 +552,20 @@ mandoc_normdate(struct roff_man *man, char *in, int ln, int pos)
a2time(&t, "%b %d, %Y", in)) {
cp = time2a(t);
if (t > time(NULL) + 86400)
mandoc_msg(MANDOCERR_DATE_FUTURE, man->parse,
ln, pos, cp);
mandoc_msg(MANDOCERR_DATE_FUTURE, ln, pos, "%s", cp);
else if (*in != '$' && strcmp(in, cp) != 0)
mandoc_msg(MANDOCERR_DATE_NORM, man->parse,
ln, pos, cp);
mandoc_msg(MANDOCERR_DATE_NORM, ln, pos, "%s", cp);
return cp;
}
/* In man(7), do not warn about the legacy format. */
if (a2time(&t, "%Y-%m-%d", in) == 0)
mandoc_msg(MANDOCERR_DATE_BAD, man->parse, ln, pos, in);
mandoc_msg(MANDOCERR_DATE_BAD, ln, pos, "%s", in);
else if (t > time(NULL) + 86400)
mandoc_msg(MANDOCERR_DATE_FUTURE, man->parse, ln, pos, in);
else if (man->macroset == MACROSET_MDOC)
mandoc_vmsg(MANDOCERR_DATE_LEGACY, man->parse,
ln, pos, "Dd %s", in);
mandoc_msg(MANDOCERR_DATE_FUTURE, ln, pos, "%s", in);
else if (man->meta.macroset == MACROSET_MDOC)
mandoc_msg(MANDOCERR_DATE_LEGACY, ln, pos, "Dd %s", in);
/* Use any non-mdoc(7) date verbatim. */

View File

@ -1,6 +1,11 @@
/* $Id: mandoc.css,v 1.36 2018/07/23 22:51:26 schwarze Exp $ */
/* $Id: mandoc.css,v 1.45 2019/03/01 10:57:18 schwarze Exp $ */
/*
* Standard style sheet for mandoc(1) -Thtml and man.cgi(8).
*
* Written by Ingo Schwarze <schwarze@openbsd.org>.
* I place this file into the public domain.
* Permission to use, copy, modify, and distribute it for any purpose
* with or without fee is hereby granted, without any conditions.
*/
/* Global defaults. */
@ -8,8 +13,16 @@
html { max-width: 65em; }
body { font-family: Helvetica,Arial,sans-serif; }
table { margin-top: 0em;
margin-bottom: 0em; }
td { vertical-align: top; }
margin-bottom: 0em;
border-collapse: collapse; }
/* Some browsers set border-color in a browser style for tbody,
* but not for table, resulting in inconsistent border styling. */
tbody { border-color: inherit; }
tr { border-color: inherit; }
td { vertical-align: top;
padding-left: 0.2em;
padding-right: 0.2em;
border-color: inherit; }
ul, ol, dl { margin-top: 0em;
margin-bottom: 0em; }
li, dt { margin-top: 1em; }
@ -52,12 +65,14 @@ td.foot-os { text-align: right; }
.manual-text {
margin-left: 3.8em; }
.Nd { display: inline; }
.Sh { margin-top: 1.2em;
.Nd { }
section.Sh { }
h1.Sh { margin-top: 1.2em;
margin-bottom: 0.6em;
margin-left: -3.2em;
font-size: 110%; }
.Ss { margin-top: 1.2em;
section.Ss { }
h2.Ss { margin-top: 1.2em;
margin-bottom: 0.6em;
margin-left: -1.2em;
font-size: 105%; }
@ -106,20 +121,25 @@ td.foot-os { text-align: right; }
.Bl-ohang > dt { }
.Bl-ohang > dd {
margin-left: 0em; }
.Bl-tag { margin-left: 5.5em; }
.Bl-tag { margin-top: 0.6em;
margin-left: 5.5em; }
.Bl-tag > dt {
float: left;
margin-top: 0em;
margin-left: -5.5em;
padding-right: 1.2em;
padding-right: 0.5em;
vertical-align: top; }
.Bl-tag > dd {
clear: right;
width: 100%;
margin-top: 0em;
margin-left: 0em;
margin-bottom: 0.6em;
vertical-align: top;
overflow: auto; }
.Bl-compact { margin-top: 0em; }
.Bl-compact > dd {
margin-bottom: 0em; }
.Bl-compact > dt {
margin-top: 0em; }
@ -151,7 +171,7 @@ td.foot-os { text-align: right; }
.RsV { }
.eqn { }
.tbl { }
.tbl td { vertical-align: middle; }
.HP { margin-left: 3.8em;
text-indent: -3.8em; }
@ -236,12 +256,86 @@ a.In { }
font-weight: normal;
font-family: monospace; }
/* Tooltip support. */
h1.Sh, h2.Ss { position: relative; }
.An, .Ar, .Cd, .Cm, .Dv, .Em, .Er, .Ev, .Fa, .Fd, .Fl, .Fn, .Ft,
.Ic, code.In, .Lb, .Lk, .Ms, .Mt, .Nd, code.Nm, .Pa, .Rs,
.St, .Sx, .Sy, .Va, .Vt, .Xr {
display: inline-block;
position: relative; }
.An::before { content: "An"; }
.Ar::before { content: "Ar"; }
.Cd::before { content: "Cd"; }
.Cm::before { content: "Cm"; }
.Dv::before { content: "Dv"; }
.Em::before { content: "Em"; }
.Er::before { content: "Er"; }
.Ev::before { content: "Ev"; }
.Fa::before { content: "Fa"; }
.Fd::before { content: "Fd"; }
.Fl::before { content: "Fl"; }
.Fn::before { content: "Fn"; }
.Ft::before { content: "Ft"; }
.Ic::before { content: "Ic"; }
code.In::before { content: "In"; }
.Lb::before { content: "Lb"; }
.Lk::before { content: "Lk"; }
.Ms::before { content: "Ms"; }
.Mt::before { content: "Mt"; }
.Nd::before { content: "Nd"; }
code.Nm::before { content: "Nm"; }
.Pa::before { content: "Pa"; }
.Rs::before { content: "Rs"; }
h1.Sh::before { content: "Sh"; }
h2.Ss::before { content: "Ss"; }
.St::before { content: "St"; }
.Sx::before { content: "Sx"; }
.Sy::before { content: "Sy"; }
.Va::before { content: "Va"; }
.Vt::before { content: "Vt"; }
.Xr::before { content: "Xr"; }
.An::before, .Ar::before, .Cd::before, .Cm::before,
.Dv::before, .Em::before, .Er::before, .Ev::before,
.Fa::before, .Fd::before, .Fl::before, .Fn::before, .Ft::before,
.Ic::before, code.In::before, .Lb::before, .Lk::before,
.Ms::before, .Mt::before, .Nd::before, code.Nm::before,
.Pa::before, .Rs::before,
h1.Sh::before, h2.Ss::before, .St::before, .Sx::before, .Sy::before,
.Va::before, .Vt::before, .Xr::before {
opacity: 0;
transition: .15s ease opacity;
pointer-events: none;
position: absolute;
bottom: 100%;
box-shadow: 0 0 .35em #000;
padding: .15em .25em;
white-space: nowrap;
font-family: Helvetica,Arial,sans-serif;
font-style: normal;
font-weight: bold;
color: black;
background: #fff; }
.An:hover::before, .Ar:hover::before, .Cd:hover::before, .Cm:hover::before,
.Dv:hover::before, .Em:hover::before, .Er:hover::before, .Ev:hover::before,
.Fa:hover::before, .Fd:hover::before, .Fl:hover::before, .Fn:hover::before,
.Ft:hover::before, .Ic:hover::before, code.In:hover::before,
.Lb:hover::before, .Lk:hover::before, .Ms:hover::before, .Mt:hover::before,
.Nd:hover::before, code.Nm:hover::before, .Pa:hover::before,
.Rs:hover::before, h1.Sh:hover::before, h2.Ss:hover::before, .St:hover::before,
.Sx:hover::before, .Sy:hover::before, .Va:hover::before, .Vt:hover::before,
.Xr:hover::before {
opacity: 1;
pointer-events: inherit; }
/* Overrides to avoid excessive margins on small devices. */
@media (max-width: 37.5em) {
.manual-text {
margin-left: 0.5em; }
.Sh, .Ss { margin-left: 0em; }
h1.Sh, h2.Ss { margin-left: 0em; }
.Bd-indent { margin-left: 2em; }
.Bl-hang > dd {
margin-left: 2em; }

View File

@ -1,7 +1,7 @@
/* $Id: mandoc.h,v 1.248 2018/07/28 18:34:15 schwarze Exp $ */
/* $Id: mandoc.h,v 1.262 2018/12/16 00:17:02 schwarze Exp $ */
/*
* Copyright (c) 2010, 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010-2018 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2012-2018 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
@ -14,6 +14,8 @@
* 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.
*
* Error handling, escape sequence, and character utilities.
*/
#define ASCII_NBRSP 31 /* non-breaking space */
@ -158,6 +160,7 @@ enum mandocerr {
MANDOCERR_LB_BAD, /* unknown library name: Lb ... */
MANDOCERR_RS_BAD, /* invalid content in Rs block: macro */
MANDOCERR_SM_BAD, /* invalid Boolean argument: macro arg */
MANDOCERR_CHAR_FONT, /* argument contains two font escapes */
MANDOCERR_FT_BAD, /* unknown font, skipping request: ft font */
MANDOCERR_TR_ODD, /* odd number of characters in request: tr char */
@ -166,6 +169,7 @@ enum mandocerr {
MANDOCERR_FI_TAB, /* tab in filled text */
MANDOCERR_EOS, /* new sentence, new line */
MANDOCERR_ESC_BAD, /* invalid escape sequence: esc */
MANDOCERR_ESC_UNDEF, /* undefined escape, printing literally: char */
MANDOCERR_STR_UNDEF, /* undefined string, using "": name */
/* related to tables */
@ -195,6 +199,7 @@ enum mandocerr {
MANDOCERR_ROFFLOOP, /* input stack limit exceeded, infinite loop? */
MANDOCERR_CHAR_BAD, /* skipping bad character: number */
MANDOCERR_MACRO, /* skipping unknown macro: macro */
MANDOCERR_REQ_NOMAC, /* skipping request outside macro: ... */
MANDOCERR_REQ_INSEC, /* skipping insecure request: request */
MANDOCERR_IT_STRAY, /* skipping item outside list: It ... */
MANDOCERR_TA_STRAY, /* skipping column outside column list: Ta */
@ -205,14 +210,18 @@ enum mandocerr {
/* related to request and macro arguments */
MANDOCERR_NAMESC, /* escaped character not allowed in a name: name */
MANDOCERR_ARG_UNDEF, /* using macro argument outside macro */
MANDOCERR_ARG_NONUM, /* argument number is not numeric */
MANDOCERR_BD_FILE, /* NOT IMPLEMENTED: Bd -file */
MANDOCERR_BD_NOARG, /* skipping display without arguments: Bd */
MANDOCERR_BL_NOTYPE, /* missing list type, using -item: Bl */
MANDOCERR_CE_NONUM, /* argument is not numeric, using 1: ce ... */
MANDOCERR_CHAR_ARG, /* argument is not a character: char ... */
MANDOCERR_NM_NONAME, /* missing manual name, using "": Nm */
MANDOCERR_OS_UNAME, /* uname(3) system call failed, using UNKNOWN */
MANDOCERR_ST_BAD, /* unknown standard specifier: St standard */
MANDOCERR_IT_NONUM, /* skipping request without numeric argument */
MANDOCERR_SHIFT, /* excessive shift: ..., but max is ... */
MANDOCERR_SO_PATH, /* NOT IMPLEMENTED: .so with absolute path or ".." */
MANDOCERR_SO_FAIL, /* .so request failed */
MANDOCERR_ARG_SKIP, /* skipping all arguments: macro args */
@ -223,7 +232,12 @@ enum mandocerr {
MANDOCERR_TOOLARGE, /* input too large */
MANDOCERR_CHAR_UNSUPP, /* unsupported control character: number */
MANDOCERR_ESC_UNSUPP, /* unsupported escape sequence: escape */
MANDOCERR_REQ_UNSUPP, /* unsupported roff request: request */
MANDOCERR_WHILE_NEST, /* nested .while loops */
MANDOCERR_WHILE_OUTOF, /* end of scope with open .while loop */
MANDOCERR_WHILE_INTO, /* end of .while loop in inner scope */
MANDOCERR_WHILE_FAIL, /* cannot continue this .while loop */
MANDOCERR_TBLOPT_EQN, /* eqn delim option in tbl: arg */
MANDOCERR_TBLLAYOUT_MOD, /* unsupported tbl layout modifier: m */
MANDOCERR_TBLMACRO, /* ignoring macro in table: macro */
@ -231,206 +245,22 @@ enum mandocerr {
MANDOCERR_MAX
};
struct tbl_opts {
char tab; /* cell-separator */
char decimal; /* decimal point */
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)
#define TBL_OPT_NOWARN (1 << 7)
int cols; /* number of columns */
int lvert; /* width of left vertical line */
int rvert; /* width of right vertical line */
};
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_MAX
};
/*
* A cell in a layout row.
*/
struct tbl_cell {
struct tbl_cell *next;
char *wstr; /* min width represented as a string */
size_t width; /* minimum column width */
size_t spacing; /* to the right of the column */
int vert; /* width of subsequent vertical line */
int col; /* column number, starting from 0 */
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 */
#define TBL_CELL_WMAX (1 << 7) /* x, X */
enum tbl_cellt pos;
};
/*
* A layout row.
*/
struct tbl_row {
struct tbl_row *next;
struct tbl_cell *first;
struct tbl_cell *last;
int vert; /* width of left vertical line */
};
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 */
struct tbl_dat *next;
char *string; /* data (NULL if not TBL_DATA_DATA) */
int spans; /* how many spans follow */
int block; /* T{ text block T} */
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_opts *opts;
struct tbl_row *layout; /* layout row */
struct tbl_dat *first;
struct tbl_dat *last;
struct tbl_span *prev;
struct tbl_span *next;
int line; /* parse line */
enum tbl_spant pos;
};
enum eqn_boxt {
EQN_TEXT, /* text (number, variable, whatever) */
EQN_SUBEXPR, /* nested `eqn' subexpression */
EQN_LIST, /* list (braces, etc.) */
EQN_PILE, /* vertical pile */
EQN_MATRIX /* pile of piles */
};
enum eqn_fontt {
EQNFONT_NONE = 0,
EQNFONT_ROMAN,
EQNFONT_BOLD,
EQNFONT_FAT,
EQNFONT_ITALIC,
EQNFONT__MAX
};
enum eqn_post {
EQNPOS_NONE = 0,
EQNPOS_SUP,
EQNPOS_SUBSUP,
EQNPOS_SUB,
EQNPOS_TO,
EQNPOS_FROM,
EQNPOS_FROMTO,
EQNPOS_OVER,
EQNPOS_SQRT,
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 *prev; /* node sibling */
struct eqn_box *parent; /* node sibling */
char *text; /* text (or NULL) */
char *left; /* fence left-hand */
char *right; /* fence right-hand */
char *top; /* expression over-symbol */
char *bottom; /* expression under-symbol */
size_t args; /* arguments in parent */
size_t expectargs; /* max arguments in parent */
enum eqn_post pos; /* position of next box */
enum eqn_fontt font; /* font of box */
enum eqn_pilet pile; /* equation piling */
};
/*
* Parse options.
*/
#define MPARSE_MDOC 1 /* assume -mdoc */
#define MPARSE_MAN 2 /* assume -man */
#define MPARSE_SO 4 /* honour .so requests */
#define MPARSE_QUICK 8 /* abort the parse early */
#define MPARSE_UTF8 16 /* accept UTF-8 input */
#define MPARSE_LATIN1 32 /* accept ISO-LATIN-1 input */
enum mandoc_os {
MANDOC_OS_OTHER = 0,
MANDOC_OS_NETBSD,
MANDOC_OS_OPENBSD
};
enum mandoc_esc {
ESCAPE_ERROR = 0, /* bail! unparsable escape */
ESCAPE_UNSUPP, /* unsupported escape; ignore it */
ESCAPE_IGNORE, /* escape to be ignored */
ESCAPE_UNDEF, /* undefined escape; print literal character */
ESCAPE_SPECIAL, /* a regular special character */
ESCAPE_FONT, /* a generic font mode */
ESCAPE_FONTBOLD, /* bold font mode */
ESCAPE_FONTITALIC, /* italic font mode */
ESCAPE_FONTBI, /* bold italic font mode */
ESCAPE_FONTROMAN, /* roman font mode */
ESCAPE_FONTCW, /* constant width font mode */
ESCAPE_FONTPREV, /* previous font mode */
ESCAPE_NUMBERED, /* a numbered glyph */
ESCAPE_UNICODE, /* a unicode codepoint */
ESCAPE_DEVICE, /* print the output device name */
ESCAPE_BREAK, /* break the output line */
ESCAPE_NOSPACE, /* suppress space if the last on a line */
ESCAPE_HORIZ, /* horizontal movement */
@ -439,14 +269,18 @@ enum mandoc_esc {
ESCAPE_OVERSTRIKE /* overstrike all chars in the argument */
};
typedef void (*mandocmsg)(enum mandocerr, enum mandoclevel,
const char *, int, int, const char *);
struct mparse;
struct roff_man;
enum mandoc_esc mandoc_font(const char *, int sz);
enum mandoc_esc mandoc_escape(const char **, const char **, int *);
void mandoc_msg_setoutfile(FILE *);
const char *mandoc_msg_getinfilename(void);
void mandoc_msg_setinfilename(const char *);
enum mandocerr mandoc_msg_getmin(void);
void mandoc_msg_setmin(enum mandocerr);
enum mandoclevel mandoc_msg_getrc(void);
void mandoc_msg_setrc(enum mandoclevel);
void mandoc_msg(enum mandocerr, int, int, const char *, ...)
__attribute__((__format__ (__printf__, 4, 5)));
void mchars_alloc(void);
void mchars_free(void);
int mchars_num2char(const char *, size_t);
@ -454,18 +288,3 @@ const char *mchars_uc2str(int);
int mchars_num2uc(const char *, size_t);
int mchars_spec2cp(const char *, size_t);
const char *mchars_spec2str(const char *, size_t, size_t *);
struct mparse *mparse_alloc(int, enum mandocerr, mandocmsg,
enum mandoc_os, const char *);
void mparse_free(struct mparse *);
void mparse_keep(struct mparse *);
int mparse_open(struct mparse *, const char *);
enum mandoclevel mparse_readfd(struct mparse *, int, const char *);
enum mandoclevel mparse_readmem(struct mparse *, void *, size_t,
const char *);
void mparse_reset(struct mparse *);
void mparse_result(struct mparse *,
struct roff_man **, char **);
const char *mparse_getkeep(const struct mparse *);
const char *mparse_strerror(enum mandocerr);
const char *mparse_strlevel(enum mandoclevel);
void mparse_updaterc(struct mparse *, enum mandoclevel *);

View File

@ -1,8 +1,8 @@
.\" $Id: mandoc_char.7,v 1.72 2018/08/08 14:30:48 schwarze Exp $
.\" $Id: mandoc_char.7,v 1.75 2018/12/15 19:30:26 schwarze Exp $
.\"
.\" Copyright (c) 2003 Jason McIntyre <jmc@openbsd.org>
.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
.\" Copyright (c) 2011, 2013, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
.\" Copyright (c) 2011,2013,2015,2017,2018 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
@ -16,7 +16,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: August 8 2018 $
.Dd $Mdocdate: December 15 2018 $
.Dt MANDOC_CHAR 7
.Os
.Sh NAME
@ -266,11 +266,13 @@ Spacing:
.It Em Input Ta Em Description
.It Sq \e\ \& Ta unpaddable non-breaking space
.It \e\(ti Ta paddable non-breaking space
.It \e0 Ta unpaddable, breaking digit-width space
.It \e0 Ta digit-width space allowing line break
.It \e| Ta one-sixth \e(em narrow space, zero width in nroff mode
.It \e^ Ta one-twelfth \e(em half-narrow space, zero width in nroff
.It \e& Ta zero-width space
.It \e& Ta zero-width non-breaking space
.It \e) Ta zero-width space transparent to end-of-sentence detection
.It \e% Ta zero-width space allowing hyphenation
.It \e: Ta zero-width space allowing line break
.El
.Pp
Lines:
@ -543,11 +545,13 @@ Accented letters:
.It \e(\(aqI Ta \('I Ta acute I
.It \e(\(aqO Ta \('O Ta acute O
.It \e(\(aqU Ta \('U Ta acute U
.It \e(\(aqY Ta \('Y Ta acute Y
.It \e(\(aqa Ta \('a Ta acute a
.It \e(\(aqe Ta \('e Ta acute e
.It \e(\(aqi Ta \('i Ta acute i
.It \e(\(aqo Ta \('o Ta acute o
.It \e(\(aqu Ta \('u Ta acute u
.It \e(\(aqy Ta \('y Ta acute y
.It \e(\(gaA Ta \(`A Ta grave A
.It \e(\(gaE Ta \(`E Ta grave E
.It \e(\(gaI Ta \(`I Ta grave I
@ -761,14 +765,16 @@ For backward compatibility with existing manuals,
.Xr mandoc 1
also supports the
.Pp
.Dl \eN\(aq Ns Ar number Ns \(aq
.Dl \eN\(aq Ns Ar number Ns \(aq and \e[ Ns Cm char Ns Ar number ]
.Pp
escape sequence, inserting the character
escape sequences, 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\(aq34\(aq, use \e(dq, or even the plain
as deprecated in the Heirloom roff manual;
on top of that, the second form is a GNU extension.
For example, do not use \eN\(aq34\(aq or \e[char34], use \e(dq,
or even the plain
.Sq \(dq
character where possible.
.Sh COMPATIBILITY

View File

@ -1,4 +1,4 @@
.Dd $Mdocdate: July 8 2017 $
.Dd $Mdocdate: December 30 2018 $
.Dt MANDOC_HEADERS 3
.Os
.Sh NAME
@ -25,15 +25,15 @@ separate from each other:
.Pp
.Bl -dash -offset indent -compact
.It
.Xr roff 7
parser
.It
.Xr mdoc 7
parser
.It
.Xr man 7
parser
.It
.Xr roff 7
parser
.It
.Xr tbl 7
parser
.It
@ -45,6 +45,8 @@ terminal formatters
HTML formatters
.It
search tools
.It
main programs
.El
.Pp
Note that mere usage of an opaque struct type does
@ -56,14 +58,18 @@ any other mandoc header.
These headers should be included before any other mandoc headers.
.Bl -tag -width Ds
.It Qq Pa mandoc_aux.h
Memory allocation utility functions; can be used everywhere.
.Pp
Requires
.In sys/types.h
for
.Vt size_t .
.Pp
Provides the utility functions documented in
Provides the functions documented in
.Xr mandoc_malloc 3 .
.It Qq Pa mandoc_ohash.h
Hashing utility functions; can be used everywhere.
.Pp
Requires
.In stddef.h
for
@ -78,73 +84,37 @@ Includes
and provides
.Fn mandoc_ohash_init .
.It Qq Pa mandoc.h
Error handling, escape sequence, and character utilities;
can be used everywhere.
.Pp
Requires
.In sys/types.h
for
.Vt size_t .
.Vt size_t
and
.In stdio.h
for
.Vt FILE .
.Pp
Provides
.Vt enum mandoc_esc ,
.Vt enum mandocerr ,
.Vt enum mandoclevel ,
.Vt enum mandoc_os ,
.Vt enum tbl_cellt ,
.Vt enum tbl_datt ,
.Vt enum tbl_spant ,
.Vt enum eqn_boxt ,
.Vt enum eqn_fontt ,
.Vt enum eqn_pilet ,
.Vt enum eqn_post ,
.Vt struct tbl_opts ,
.Vt struct tbl_cell ,
.Vt struct tbl_row ,
.Vt struct tbl_dat ,
.Vt struct tbl_span ,
.Vt struct eqn_box ,
the function prototype typedef
.Fn mandocmsg ,
the function
.Xr mandoc_escape 3 ,
the functions described in
.Xr mchars_alloc 3 ,
and the functions
.Fn mparse_*
described in
.Xr mandoc 3 .
.Pp
Uses the opaque type
.Vt struct mparse
from
.Pa read.c
for function prototypes.
Uses the type
.Vt struct roff_man
from
.Pa roff.h
as an opaque type for function prototypes.
.It Qq Pa mandoc_xr.h
Provides
.Vt struct mandoc_xr
and the functions
.Fn mandoc_xr_reset ,
.Fn mandoc_xr_add ,
.Fn mandoc_xr_get ,
and
.Fn mandoc_xr_free .
and the
.Fn mandoc_msg*
functions.
.It Qq Pa roff.h
Requires
.Qq Pa mandoc_ohash.h
for
.Vt struct ohash
and
.Qq Pa mandoc.h
for
.Vt enum mandoc_os .
Common data types for all syntax trees and related functions;
can be used everywhere.
.Pp
Provides
.Vt enum mandoc_os ,
.Vt enum mdoc_endbody ,
.Vt enum roff_macroset ,
.Vt enum roff_next ,
.Vt enum roff_sec ,
.Vt enum roff_tok ,
.Vt enum roff_type ,
@ -153,21 +123,99 @@ Provides
.Vt struct roff_node ,
the constant array
.Va roff_name
and the functions
.Fn deroff ,
.Fn roffhash_alloc ,
.Fn roffhash_find ,
.Fn roffhash_free ,
and
.Fn roff_validate .
and the function
.Fn deroff .
.Pp
Uses pointers to the types
.Vt struct ohash
from
.Pa mandoc_ohash.h ,
.Vt struct mdoc_arg
and
.Vt union mdoc_data
from
.Pa mdoc.h
.Pa mdoc.h ,
.Vt struct tbl_span
from
.Pa tbl.h ,
and
.Vt struct eqn_box
from
.Pa eqn.h
as opaque struct members.
.It Qq Pa tbl.h
Data structures for the
.Xr tbl 7
parse tree; can be used everywhere.
.Pp
Requires
.In sys/types.h
for
.Vt size_t .
.Pp
Provides
.Vt enum tbl_cellt ,
.Vt enum tbl_datt ,
.Vt enum tbl_spant ,
.Vt struct tbl_opts ,
.Vt struct tbl_cell ,
.Vt struct tbl_row ,
.Vt struct tbl_dat ,
and
.Vt struct tbl_span .
.It Qq Pa eqn.h
Data structures for the
.Xr eqn 7
parse tree; can be used everywhere.
.Pp
Requires
.In sys/types.h
for
.Vt size_t .
.Pp
Provides
.Vt enum eqn_boxt ,
.Vt enum eqn_fontt ,
.Vt enum eqn_post ,
and
.Vt struct eqn_box .
.It Qq Pa mandoc_parse.h
Top level parser interface, for use in the main program
and in the main parser, but not in formatters.
.Pp
Requires
.Pa mandoc.h
for
.Vt enum mandocerr
and
.Vt enum mandoclevel
and
.Pa roff.h
for
.Vt enum mandoc_os .
.Pp
Uses the opaque type
.Vt struct mparse
from
.Pa read.c
for function prototypes.
Uses
.Vt struct roff_meta
from
.Pa roff.h
as an opaque type for function prototypes.
.It Qq Pa mandoc_xr.h
Cross reference validation; intended for use in the main program
and in parsers, but not in formatters.
.Pp
Provides
.Vt struct mandoc_xr
and the functions
.Fn mandoc_xr_reset ,
.Fn mandoc_xr_add ,
.Fn mandoc_xr_get ,
and
.Fn mandoc_xr_free .
.El
.Pp
The following two require
@ -200,27 +248,24 @@ and the functions
described in
.Xr mandoc 3 .
.Pp
Uses the type
.Vt struct roff_man
Uses the types
.Vt struct roff_node
from
.Pa roff.h
as an opaque type for function prototypes.
and
.Vt struct roff_man
from
.Pa roff_int.h
as opaque types for function prototypes.
.Pp
When this header is included, the same file should not include
.Pa libman.h
or
.Pa libroff.h .
internals of different parsers.
.It Qq Pa man.h
Provides the functions
.Fn man_*
described in
.Xr mandoc 3 .
.Pp
Uses the opaque type
.Vt struct mparse
from
.Pa read.c
for function prototypes.
Uses the type
.Vt struct roff_man
from
@ -228,12 +273,10 @@ from
as an opaque type for function prototypes.
.Pp
When this header is included, the same file should not include
.Pa libmdoc.h
or
.Pa libroff.h .
internals of different parsers.
.El
.Ss Parser internals
The following headers require inclusion of a parser interface header
Most of the following headers require inclusion of a parser interface header
before they can be included.
All parser interface headers should precede all parser internal headers.
When any parser internal headers are included, the same file should
@ -250,16 +293,11 @@ for
.Vt enum mandocerr .
.Pp
Provides
.Vt enum rofferr ,
.Vt struct buf ,
utility functions needed by multiple parsers,
and the top-level functions to call the parsers.
.Pp
Uses the opaque types
.Vt struct mparse
from
.Pa read.c
and
Uses the opaque type
.Vt struct roff
from
.Pa roff.c
@ -270,14 +308,28 @@ from
.Pa roff.h
as an opaque type for function prototypes.
.It Qq Pa roff_int.h
Parser internals shared by multiple parsers.
Can be used in all parsers, but not in main programs or formatters.
.Pp
Requires
.Qq Pa roff.h
for
.Vt enum roff_type .
.Vt enum roff_type
and
.Vt enum roff_tok .
.Pp
Provides functions named
Provides
.Vt enum roff_next ,
.Vt struct roff_man ,
functions named
.Fn roff_*
to handle roff nodes and the two special functions
to handle roff nodes,
.Fn roffhash_alloc ,
.Fn roffhash_find ,
.Fn roffhash_free ,
and
.Fn roff_validate ,
and the two special functions
.Fn man_breakscope
and
.Fn mdoc_argv_free
@ -285,11 +337,17 @@ because the latter two are needed by
.Qq Pa roff.c .
.Pp
Uses the types
.Vt struct roff_man
and
.Vt struct roff_node
.Vt struct ohash
from
.Pa roff.h
.Pa mandoc_ohash.h ,
.Vt struct roff_node
and
.Vt struct roff_meta
from
.Pa roff.h ,
.Vt struct roff
from
.Pa roff.c ,
and
.Vt struct mdoc_arg
from
@ -301,11 +359,7 @@ Requires
for
.Vt enum roff_tok
and
.Qq Pa mdoc.h
for
.Vt enum mdoc_*
and
.Vt struct mdoc_* .
.Vt enum roff_sec .
.Pp
Provides
.Vt enum margserr ,
@ -315,23 +369,21 @@ and many functions internal to the
.Xr mdoc 7
parser.
.Pp
Uses the opaque type
.Vt struct mparse
from
.Pa read.c .
Uses the types
.Vt struct roff_man
and
.Vt struct roff_node
from
.Pa roff.h
.Pa roff.h ,
.Vt struct roff_man
from
.Pa roff_int.h ,
and
.Vt struct mdoc_arg
from
.Pa mdoc.h
as opaque types for function prototypes.
.Pp
When this header is included, the same file should not include
.Pa man.h ,
.Pa libman.h ,
or
.Pa libroff.h .
interfaces of different parsers.
.It Qq Pa libman.h
Requires
.Qq Pa roff.h
@ -345,52 +397,109 @@ and some functions internal to the
parser.
.Pp
Uses the types
.Vt struct roff_man
and
.Vt struct roff_node
from
.Pa roff.h
and
.Vt struct roff_man
from
.Pa roff_int.h
as opaque types for function prototypes.
.Pp
When this header is included, the same file should not include
.Pa mdoc.h ,
.Pa libmdoc.h ,
or
.Pa libroff.h .
.It Qq Pa libroff.h
interfaces of different parsers.
.It Qq Pa eqn_parse.h
External interface of the
.Xr eqn 7
parser, for use in the
.Xr roff 7
and
.Xr eqn 7
parsers only.
.Pp
Requires
.In sys/types.h
for
.Vt size_t
.Vt size_t .
.Pp
Provides
.Vt struct eqn_node
and the functions
.Fn eqn_alloc ,
.Fn eqn_box_new ,
.Fn eqn_box_free ,
.Fn eqn_free ,
.Fn eqn_parse ,
.Fn eqn_read ,
and
.Qq Pa mandoc.h
.Fn eqn_reset .
.Pp
Uses the type
.Vt struct eqn_box
from
.Pa mandoc.h
as an opaque type for function prototypes.
Uses the types
.Vt struct roff_node
from
.Pa roff.h
and
.Vt struct eqn_def
from
.Pa eqn.c
as opaque struct members.
.Pp
When this header is included, the same file should not include
internals of different parsers.
.It Qq Pa tbl_parse.h
External interface of the
.Xr tbl 7
parser, for use in the
.Xr roff 7
and
.Xr tbl 7
parsers only.
.Pp
Provides the functions documented in
.Xr tbl 3 .
.Pp
Uses the types
.Vt struct tbl_span
from
.Pa tbl.h
and
.Vt struct tbl_node
from
.Pa tbl_int.h
as opaque types for function prototypes.
.Pp
When this header is included, the same file should not include
internals of different parsers.
.It Qq Pa tbl_int.h
Internal interfaces of the
.Xr tbl 7
parser, for use inside the
.Xr tbl 7
parser only.
.Pp
Requires
.Qq Pa tbl.h
for
.Vt struct tbl_*
and
.Vt struct eqn_box .
.Vt struct tbl_opts .
.Pp
Provides
.Vt enum tbl_part ,
.Vt struct tbl_node ,
.Vt struct eqn_def ,
.Vt struct eqn_node ,
and many functions internal to the
.Xr tbl 7
and the functions
.Fn tbl_option ,
.Fn tbl_layout ,
.Fn tbl_data ,
.Fn tbl_cdata ,
and
.Xr eqn 7
parsers.
.Pp
Uses the opaque type
.Vt struct mparse
from
.Pa read.c .
.Fn tbl_reset .
.Pp
When this header is included, the same file should not include
.Pa man.h ,
.Pa mdoc.h ,
.Pa libman.h ,
or
.Pa libmdoc.h .
interfaces of different parsers.
.El
.Ss Formatter interface
These headers should be included after any parser interface headers.
@ -466,7 +575,10 @@ or
Requires
.In sys/types.h
for
.Vt size_t
.Vt size_t ,
.Pa mandoc.h
for
.Vt enum mandoc_esc ,
and
.Qq Pa out.h
for
@ -517,7 +629,7 @@ functionality mentioned in
Provides the top level steering functions for all formatters.
.Pp
Uses the type
.Vt struct roff_man
.Vt struct roff_meta
from
.Pa roff.h
as an opaque type for function prototypes.

View File

@ -1,4 +1,4 @@
.\" $Id: mandoc_html.3,v 1.17 2018/06/25 16:54:59 schwarze Exp $
.\" $Id: mandoc_html.3,v 1.19 2019/01/11 12:56:43 schwarze Exp $
.\"
.\" Copyright (c) 2014, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
.\"
@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: June 25 2018 $
.Dd $Mdocdate: January 11 2019 $
.Dt MANDOC_HTML 3
.Os
.Sh NAME
@ -167,11 +167,6 @@ the respective attribute is not written.
Print a
.Cm class
attribute.
This attribute letter can optionally be followed by the modifier letter
.Cm T .
In that case, a
.Cm title
attribute with the same value is also printed.
.It Cm h
Print a
.Cm href
@ -216,6 +211,14 @@ It requires two
.Va char *
arguments.
The first is the name of the style property, the second its value.
The name must not be
.Dv NULL .
The
.Cm s
.Ar fmt
letter can be repeated, each repetition requiring an additional pair of
.Va char *
arguments.
.El
.Pp
.Fn print_otag

329
contrib/mandoc/mandoc_msg.c Normal file
View File

@ -0,0 +1,329 @@
/* $Id: mandoc_msg.c,v 1.6 2019/03/06 15:55:38 schwarze Exp $ */
/*
* Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014,2015,2016,2017,2018 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.
*/
#include "config.h"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include "mandoc.h"
static const enum mandocerr lowest_type[MANDOCLEVEL_MAX] = {
MANDOCERR_OK,
MANDOCERR_OK,
MANDOCERR_WARNING,
MANDOCERR_ERROR,
MANDOCERR_UNSUPP,
MANDOCERR_MAX,
MANDOCERR_MAX
};
static const char *const level_name[MANDOCLEVEL_MAX] = {
"SUCCESS",
"STYLE",
"WARNING",
"ERROR",
"UNSUPP",
"BADARG",
"SYSERR"
};
static const char *const type_message[MANDOCERR_MAX] = {
"ok",
"base system convention",
"Mdocdate found",
"Mdocdate missing",
"unknown architecture",
"operating system explicitly specified",
"RCS id missing",
"referenced manual not found",
"generic style suggestion",
"legacy man(7) date format",
"normalizing date format to",
"lower case character in document title",
"duplicate RCS id",
"possible typo in section name",
"unterminated quoted argument",
"useless macro",
"consider using OS macro",
"errnos out of order",
"duplicate errno",
"trailing delimiter",
"no blank before trailing delimiter",
"fill mode already enabled, skipping",
"fill mode already disabled, skipping",
"verbatim \"--\", maybe consider using \\(em",
"function name without markup",
"whitespace at end of input line",
"bad comment style",
"generic warning",
/* related to the prologue */
"missing manual title, using UNTITLED",
"missing manual title, using \"\"",
"missing manual section, using \"\"",
"unknown manual section",
"missing date, using today's date",
"cannot parse date, using it verbatim",
"date in the future, using it anyway",
"missing Os macro, using \"\"",
"late prologue macro",
"prologue macros out of order",
/* related to document structure */
".so is fragile, better use ln(1)",
"no document body",
"content before first section header",
"first section is not \"NAME\"",
"NAME section without Nm before Nd",
"NAME section without description",
"description not at the end of NAME",
"bad NAME section content",
"missing comma before name",
"missing description line, using \"\"",
"description line outside NAME section",
"sections out of conventional order",
"duplicate section title",
"unexpected section",
"cross reference to self",
"unusual Xr order",
"unusual Xr punctuation",
"AUTHORS section without An macro",
/* related to macros and nesting */
"obsolete macro",
"macro neither callable nor escaped",
"skipping paragraph macro",
"moving paragraph macro out of list",
"skipping no-space macro",
"blocks badly nested",
"nested displays are not portable",
"moving content out of list",
"first macro on line",
"line scope broken",
"skipping blank line in line scope",
/* related to missing macro arguments */
"skipping empty request",
"conditional request controls empty scope",
"skipping empty macro",
"empty block",
"empty argument, using 0n",
"missing display type, using -ragged",
"list type is not the first argument",
"missing -width in -tag list, using 6n",
"missing utility name, using \"\"",
"missing function name, using \"\"",
"empty head in list item",
"empty list item",
"missing argument, using next line",
"missing font type, using \\fR",
"unknown font type, using \\fR",
"nothing follows prefix",
"empty reference block",
"missing section argument",
"missing -std argument, adding it",
"missing option string, using \"\"",
"missing resource identifier, using \"\"",
"missing eqn box, using \"\"",
/* related to bad macro arguments */
"duplicate argument",
"skipping duplicate argument",
"skipping duplicate display type",
"skipping duplicate list type",
"skipping -width argument",
"wrong number of cells",
"unknown AT&T UNIX version",
"comma in function argument",
"parenthesis in function name",
"unknown library name",
"invalid content in Rs block",
"invalid Boolean argument",
"argument contains two font escapes",
"unknown font, skipping request",
"odd number of characters in request",
/* related to plain text */
"blank line in fill mode, using .sp",
"tab in filled text",
"new sentence, new line",
"invalid escape sequence",
"undefined escape, printing literally",
"undefined string, using \"\"",
/* related to tables */
"tbl line starts with span",
"tbl column starts with span",
"skipping vertical bar in tbl layout",
"generic error",
/* related to tables */
"non-alphabetic character in tbl options",
"skipping unknown tbl option",
"missing tbl option argument",
"wrong tbl option argument size",
"empty tbl layout",
"invalid character in tbl layout",
"unmatched parenthesis in tbl layout",
"tbl without any data cells",
"ignoring data in spanned tbl cell",
"ignoring extra tbl data cells",
"data block open at end of tbl",
/* related to document structure and macros */
NULL,
"duplicate prologue macro",
"skipping late title macro",
"input stack limit exceeded, infinite loop?",
"skipping bad character",
"skipping unknown macro",
"ignoring request outside macro",
"skipping insecure request",
"skipping item outside list",
"skipping column outside column list",
"skipping end of block that is not open",
"fewer RS blocks open, skipping",
"inserting missing end of block",
"appending missing end of block",
/* related to request and macro arguments */
"escaped character not allowed in a name",
"using macro argument outside macro",
"argument number is not numeric",
"NOT IMPLEMENTED: Bd -file",
"skipping display without arguments",
"missing list type, using -item",
"argument is not numeric, using 1",
"argument is not a character",
"missing manual name, using \"\"",
"uname(3) system call failed, using UNKNOWN",
"unknown standard specifier",
"skipping request without numeric argument",
"excessive shift",
"NOT IMPLEMENTED: .so with absolute path or \"..\"",
".so request failed",
"skipping all arguments",
"skipping excess arguments",
"divide by zero",
"unsupported feature",
"input too large",
"unsupported control character",
"unsupported escape sequence",
"unsupported roff request",
"nested .while loops",
"end of scope with open .while loop",
"end of .while loop in inner scope",
"cannot continue this .while loop",
"eqn delim option in tbl",
"unsupported tbl layout modifier",
"ignoring macro in table",
};
static FILE *fileptr = NULL;
static const char *filename = NULL;
static enum mandocerr min_type = MANDOCERR_MAX;
static enum mandoclevel rc = MANDOCLEVEL_OK;
void
mandoc_msg_setoutfile(FILE *fp)
{
fileptr = fp;
}
const char *
mandoc_msg_getinfilename(void)
{
return filename;
}
void
mandoc_msg_setinfilename(const char *fn)
{
filename = fn;
}
enum mandocerr
mandoc_msg_getmin(void)
{
return min_type;
}
void
mandoc_msg_setmin(enum mandocerr t)
{
min_type = t;
}
enum mandoclevel
mandoc_msg_getrc(void)
{
return rc;
}
void
mandoc_msg_setrc(enum mandoclevel level)
{
if (rc < level)
rc = level;
}
void
mandoc_msg(enum mandocerr t, int line, int col, const char *fmt, ...)
{
va_list ap;
enum mandoclevel level;
if (t < min_type && t != MANDOCERR_FILE)
return;
level = MANDOCLEVEL_UNSUPP;
while (t < lowest_type[level])
level--;
mandoc_msg_setrc(level);
if (fileptr == NULL)
return;
fprintf(fileptr, "%s:", getprogname());
if (filename != NULL)
fprintf(fileptr, " %s:", filename);
if (line > 0)
fprintf(fileptr, "%d:%d:", line, col + 1);
fprintf(fileptr, " %s", level_name[level]);
if (type_message[t] != NULL)
fprintf(fileptr, ": %s", type_message[t]);
if (fmt != NULL) {
fprintf(fileptr, ": ");
va_start(ap, fmt);
vfprintf(fileptr, fmt, ap);
va_end(ap);
}
fputc('\n', fileptr);
}

View File

@ -0,0 +1,43 @@
/* $Id: mandoc_parse.h,v 1.4 2018/12/30 00:49:55 schwarze Exp $ */
/*
* Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014,2015,2016,2017,2018 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.
*
* Top level parser interface. For use in the main program
* and in the main parser, but not in formatters.
*/
/*
* Parse options.
*/
#define MPARSE_MDOC (1 << 0) /* assume -mdoc */
#define MPARSE_MAN (1 << 1) /* assume -man */
#define MPARSE_SO (1 << 2) /* honour .so requests */
#define MPARSE_QUICK (1 << 3) /* abort the parse early */
#define MPARSE_UTF8 (1 << 4) /* accept UTF-8 input */
#define MPARSE_LATIN1 (1 << 5) /* accept ISO-LATIN-1 input */
#define MPARSE_VALIDATE (1 << 6) /* call validation functions */
struct roff_meta;
struct mparse;
struct mparse *mparse_alloc(int, enum mandoc_os, const char *);
void mparse_copy(const struct mparse *);
void mparse_free(struct mparse *);
int mparse_open(struct mparse *, const char *);
void mparse_readfd(struct mparse *, int, const char *);
void mparse_reset(struct mparse *);
struct roff_meta *mparse_result(struct mparse *);

View File

@ -1,7 +1,7 @@
/* $Id: mandocd.c,v 1.6 2017/06/24 14:38:32 schwarze Exp $ */
/* $Id: mandocd.c,v 1.11 2019/03/03 13:02:11 schwarze Exp $ */
/*
* Copyright (c) 2017 Michael Stapelberg <stapelberg@debian.org>
* Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2017, 2019 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
@ -38,6 +38,7 @@
#include "roff.h"
#include "mdoc.h"
#include "man.h"
#include "mandoc_parse.h"
#include "main.h"
#include "manconf.h"
@ -170,8 +171,8 @@ main(int argc, char *argv[])
errx(1, "file descriptor %s %s", argv[1], errstr);
mchars_alloc();
parser = mparse_alloc(MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1,
MANDOCERR_MAX, NULL, MANDOC_OS_OTHER, defos);
parser = mparse_alloc(MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1 |
MPARSE_VALIDATE, MANDOC_OS_OTHER, defos);
memset(&options, 0, sizeof(options));
switch (outtype) {
@ -212,6 +213,8 @@ main(int argc, char *argv[])
process(parser, outtype, formatter);
mparse_reset(parser);
if (outtype == OUTT_HTML)
html_reset(formatter);
fflush(stdout);
fflush(stderr);
@ -243,35 +246,29 @@ main(int argc, char *argv[])
static void
process(struct mparse *parser, enum outt outtype, void *formatter)
{
struct roff_man *man;
struct roff_meta *meta;
mparse_readfd(parser, STDIN_FILENO, "<unixfd>");
mparse_result(parser, &man, NULL);
if (man == NULL)
return;
if (man->macroset == MACROSET_MDOC) {
mdoc_validate(man);
meta = mparse_result(parser);
if (meta->macroset == MACROSET_MDOC) {
switch (outtype) {
case OUTT_ASCII:
case OUTT_UTF8:
terminal_mdoc(formatter, man);
terminal_mdoc(formatter, meta);
break;
case OUTT_HTML:
html_mdoc(formatter, man);
html_mdoc(formatter, meta);
break;
}
}
if (man->macroset == MACROSET_MAN) {
man_validate(man);
if (meta->macroset == MACROSET_MAN) {
switch (outtype) {
case OUTT_ASCII:
case OUTT_UTF8:
terminal_man(formatter, man);
terminal_man(formatter, meta);
break;
case OUTT_HTML:
html_man(formatter, man);
html_man(formatter, meta);
break;
}
}

View File

@ -1,7 +1,7 @@
/* $Id: mandocdb.c,v 1.258 2018/02/23 18:25:57 schwarze Exp $ */
/* $Id: mandocdb.c,v 1.262 2018/12/30 00:49:55 schwarze Exp $ */
/*
* Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011-2017 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2011-2018 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2016 Ed Maste <emaste@freebsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
@ -52,6 +52,7 @@
#include "roff.h"
#include "mdoc.h"
#include "man.h"
#include "mandoc_parse.h"
#include "manconf.h"
#include "mansearch.h"
#include "dba_array.h"
@ -185,7 +186,7 @@ static struct ohash names; /* table of all names */
static struct ohash strings; /* table of all strings */
static uint64_t name_mask;
static const struct mdoc_handler __mdocs[MDOC_MAX - MDOC_Dd] = {
static const struct mdoc_handler mdoc_handlers[MDOC_MAX - MDOC_Dd] = {
{ NULL, 0, NODE_NOPRT }, /* Dd */
{ NULL, 0, NODE_NOPRT }, /* Dt */
{ NULL, 0, NODE_NOPRT }, /* Os */
@ -307,7 +308,6 @@ static const struct mdoc_handler __mdocs[MDOC_MAX - MDOC_Dd] = {
{ NULL, 0, 0 }, /* %U */
{ NULL, 0, 0 }, /* Ta */
};
static const struct mdoc_handler *const mdocs = __mdocs - MDOC_Dd;
int
@ -347,6 +347,7 @@ mandocdb(int argc, char *argv[])
goto usage; \
} while (/*CONSTCOND*/0)
mparse_options = MPARSE_VALIDATE;
path_arg = NULL;
op = OP_DEFAULT;
@ -422,8 +423,7 @@ mandocdb(int argc, char *argv[])
exitcode = (int)MANDOCLEVEL_OK;
mchars_alloc();
mp = mparse_alloc(mparse_options, MANDOCERR_MAX, NULL,
MANDOC_OS_OTHER, NULL);
mp = mparse_alloc(mparse_options, MANDOC_OS_OTHER, NULL);
mandoc_ohash_init(&mpages, 6, offsetof(struct mpage, inodev));
mandoc_ohash_init(&mlinks, 6, offsetof(struct mlink, file));
@ -1116,8 +1116,7 @@ mpages_merge(struct dba *dba, struct mparse *mp)
{
struct mpage *mpage, *mpage_dest;
struct mlink *mlink, *mlink_dest;
struct roff_man *man;
char *sodest;
struct roff_meta *meta;
char *cp;
int fd;
@ -1130,8 +1129,7 @@ mpages_merge(struct dba *dba, struct mparse *mp)
mandoc_ohash_init(&names, 4, offsetof(struct str, key));
mandoc_ohash_init(&strings, 6, offsetof(struct str, key));
mparse_reset(mp);
man = NULL;
sodest = NULL;
meta = NULL;
if ((fd = mparse_open(mp, mlink->file)) == -1) {
say(mlink->file, "&open");
@ -1146,14 +1144,14 @@ mpages_merge(struct dba *dba, struct mparse *mp)
mparse_readfd(mp, fd, mlink->file);
close(fd);
fd = -1;
mparse_result(mp, &man, &sodest);
meta = mparse_result(mp);
}
if (sodest != NULL) {
if (meta != NULL && meta->sodest != NULL) {
mlink_dest = ohash_find(&mlinks,
ohash_qlookup(&mlinks, sodest));
ohash_qlookup(&mlinks, meta->sodest));
if (mlink_dest == NULL) {
mandoc_asprintf(&cp, "%s.gz", sodest);
mandoc_asprintf(&cp, "%s.gz", meta->sodest);
mlink_dest = ohash_find(&mlinks,
ohash_qlookup(&mlinks, cp));
free(cp);
@ -1190,39 +1188,36 @@ mpages_merge(struct dba *dba, struct mparse *mp)
mpage->mlinks = NULL;
}
goto nextpage;
} else if (man != NULL && man->macroset == MACROSET_MDOC) {
mdoc_validate(man);
} else if (meta != NULL && meta->macroset == MACROSET_MDOC) {
mpage->form = FORM_SRC;
mpage->sec = man->meta.msec;
mpage->sec = meta->msec;
mpage->sec = mandoc_strdup(
mpage->sec == NULL ? "" : mpage->sec);
mpage->arch = man->meta.arch;
mpage->arch = meta->arch;
mpage->arch = mandoc_strdup(
mpage->arch == NULL ? "" : mpage->arch);
mpage->title = mandoc_strdup(man->meta.title);
} else if (man != NULL && man->macroset == MACROSET_MAN) {
man_validate(man);
if (*man->meta.msec != '\0' ||
*man->meta.title != '\0') {
mpage->title = mandoc_strdup(meta->title);
} else if (meta != NULL && meta->macroset == MACROSET_MAN) {
if (*meta->msec != '\0' || *meta->title != '\0') {
mpage->form = FORM_SRC;
mpage->sec = mandoc_strdup(man->meta.msec);
mpage->sec = mandoc_strdup(meta->msec);
mpage->arch = mandoc_strdup(mlink->arch);
mpage->title = mandoc_strdup(man->meta.title);
mpage->title = mandoc_strdup(meta->title);
} else
man = NULL;
meta = NULL;
}
assert(mpage->desc == NULL);
if (man == NULL) {
if (meta == NULL) {
mpage->form = FORM_CAT;
mpage->sec = mandoc_strdup(mlink->dsec);
mpage->arch = mandoc_strdup(mlink->arch);
mpage->title = mandoc_strdup(mlink->name);
parse_cat(mpage, fd);
} else if (man->macroset == MACROSET_MDOC)
parse_mdoc(mpage, &man->meta, man->first);
} else if (meta->macroset == MACROSET_MDOC)
parse_mdoc(mpage, meta, meta->first);
else
parse_man(mpage, &man->meta, man->first);
parse_man(mpage, meta, meta->first);
if (mpage->desc == NULL) {
mpage->desc = mandoc_strdup(mlink->name);
if (warnings)
@ -1546,25 +1541,28 @@ static void
parse_mdoc(struct mpage *mpage, const struct roff_meta *meta,
const struct roff_node *n)
{
const struct mdoc_handler *handler;
for (n = n->child; n != NULL; n = n->next) {
if (n->tok == TOKEN_NONE ||
n->tok < ROFF_MAX ||
n->flags & mdocs[n->tok].taboo)
if (n->tok == TOKEN_NONE || n->tok < ROFF_MAX)
continue;
assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);
handler = mdoc_handlers + (n->tok - MDOC_Dd);
if (n->flags & handler->taboo)
continue;
switch (n->type) {
case ROFFT_ELEM:
case ROFFT_BLOCK:
case ROFFT_HEAD:
case ROFFT_BODY:
case ROFFT_TAIL:
if (mdocs[n->tok].fp != NULL &&
(*mdocs[n->tok].fp)(mpage, meta, n) == 0)
if (handler->fp != NULL &&
(*handler->fp)(mpage, meta, n) == 0)
break;
if (mdocs[n->tok].mask)
if (handler->mask)
putmdockey(mpage, n->child,
mdocs[n->tok].mask, mdocs[n->tok].taboo);
handler->mask, handler->taboo);
break;
default:
continue;

View File

@ -1,6 +1,6 @@
/* $Id: manpath.c,v 1.35 2017/07/01 09:47:30 schwarze Exp $ */
/* $Id: manpath.c,v 1.37 2018/11/22 11:30:23 schwarze Exp $ */
/*
* Copyright (c) 2011, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2011,2014,2015,2017,2018 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
@ -232,8 +232,8 @@ int
manconf_output(struct manoutput *conf, const char *cp, int fromfile)
{
const char *const toks[] = {
"includes", "man", "paper", "style",
"indent", "width", "fragment", "mdoc", "noval"
"includes", "man", "paper", "style", "indent", "width",
"tag", "fragment", "mdoc", "noval", "toc"
};
const char *errstr;
@ -257,7 +257,7 @@ manconf_output(struct manoutput *conf, const char *cp, int fromfile)
warnx("-O %s=?: Missing argument value", toks[tok]);
return -1;
}
if ((tok == 6 || tok == 7) && *cp != '\0') {
if (tok > 6 && *cp != '\0') {
warnx("-O %s: Does not take a value: %s", toks[tok], cp);
return -1;
}
@ -312,14 +312,24 @@ manconf_output(struct manoutput *conf, const char *cp, int fromfile)
warnx("-O width=%s is %s", cp, errstr);
return -1;
case 6:
conf->fragment = 1;
if (conf->tag != NULL) {
oldval = mandoc_strdup(conf->tag);
break;
}
conf->tag = mandoc_strdup(cp);
return 0;
case 7:
conf->mdoc = 1;
conf->fragment = 1;
return 0;
case 8:
conf->mdoc = 1;
return 0;
case 9:
conf->noval = 1;
return 0;
case 10:
conf->toc = 1;
return 0;
default:
if (fromfile)
warnx("-O %s: Bad argument", cp);

View File

@ -1,7 +1,7 @@
/* $Id: mansearch.c,v 1.77 2017/08/22 17:50:11 schwarze Exp $ */
/* $Id: mansearch.c,v 1.80 2018/12/13 11:55:46 schwarze Exp $ */
/*
* Copyright (c) 2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013-2017 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2013-2018 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
@ -36,7 +36,6 @@
#include <string.h>
#include <unistd.h>
#include "mandoc.h"
#include "mandoc_aux.h"
#include "mandoc_ohash.h"
#include "manconf.h"
@ -201,7 +200,6 @@ mansearch(const struct mansearch *search,
mpage->names = buildnames(page);
mpage->output = buildoutput(outkey, page);
mpage->ipath = i;
mpage->bits = rp->bits;
mpage->sec = *page->sect - '0';
if (mpage->sec < 0 || mpage->sec > 9)
mpage->sec = 10;
@ -296,10 +294,8 @@ manmerge_term(struct expr *e, struct ohash *htab)
break;
slot = ohash_lookup_memory(htab,
(char *)&res, sizeof(res.page), res.page);
if ((rp = ohash_find(htab, slot)) != NULL) {
rp->bits |= res.bits;
if ((rp = ohash_find(htab, slot)) != NULL)
continue;
}
rp = mandoc_malloc(sizeof(*rp));
*rp = res;
ohash_insert(htab, slot, rp);
@ -412,8 +408,7 @@ manpage_compare(const void *vp1, const void *vp2)
mp1 = vp1;
mp2 = vp2;
if ((diff = mp2->bits - mp1->bits) ||
(diff = mp1->sec - mp2->sec))
if ((diff = mp1->sec - mp2->sec))
return diff;
/* Fall back to alphabetic ordering of names. */
@ -774,8 +769,9 @@ exprterm(const struct mansearch *search, int argc, char *argv[], int *argi)
cs = 0;
} else if ((val = strpbrk(argv[*argi], "=~")) == NULL) {
e->bits = TYPE_Nm | TYPE_Nd;
e->match.type = DBM_SUB;
e->match.str = argv[*argi];
e->match.type = DBM_REGEX;
val = argv[*argi];
cs = 0;
} else {
if (val == argv[*argi])
e->bits = TYPE_Nm | TYPE_Nd;

View File

@ -1,4 +1,4 @@
/* $Id: mansearch.h,v 1.28 2017/04/17 20:05:08 schwarze Exp $ */
/* $Id: mansearch.h,v 1.29 2018/11/22 12:01:46 schwarze Exp $ */
/*
* Copyright (c) 2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013, 2014, 2016, 2017 Ingo Schwarze <schwarze@openbsd.org>
@ -93,7 +93,6 @@ struct manpage {
char *names; /* a list of names with sections */
char *output; /* user-defined additional output */
size_t ipath; /* number of the manpath */
uint64_t bits; /* name type mask */
int sec; /* section number, 10 means invalid */
enum form form;
};

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
/* $Id: mdoc.c,v 1.268 2017/08/11 16:56:21 schwarze Exp $ */
/* $Id: mdoc.c,v 1.274 2018/12/31 07:46:07 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010, 2012-2017 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2010, 2012-2018 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
@ -79,13 +79,6 @@ mdoc_parseln(struct roff_man *mdoc, int ln, char *buf, int offs)
mdoc_ptext(mdoc, ln, buf, offs);
}
void
mdoc_macro(MACRO_PROT_ARGS)
{
assert(tok >= MDOC_Dd && tok < MDOC_MAX);
(*mdoc_macros[tok].fp)(mdoc, tok, line, ppos, pos, buf);
}
void
mdoc_tail_alloc(struct roff_man *mdoc, int line, int pos, enum roff_tok tok)
{
@ -162,15 +155,6 @@ mdoc_elem_alloc(struct roff_man *mdoc, int line, int pos,
mdoc->next = ROFF_NEXT_CHILD;
}
void
mdoc_node_relink(struct roff_man *mdoc, struct roff_node *p)
{
roff_node_unlink(mdoc, p);
p->prev = p->next = NULL;
roff_node_append(mdoc, p);
}
/*
* Parse free-form text, that is, a line that does not begin with the
* control character.
@ -196,7 +180,8 @@ mdoc_ptext(struct roff_man *mdoc, int line, char *buf, int offs)
(n->parent != NULL && n->parent->tok == MDOC_Bl &&
n->parent->norm->Bl.type == LIST_column)) {
mdoc->flags |= MDOC_FREECOL;
mdoc_macro(mdoc, MDOC_It, line, offs, &offs, buf);
(*mdoc_macro(MDOC_It)->fp)(mdoc, MDOC_It,
line, offs, &offs, buf);
return 1;
}
@ -225,7 +210,7 @@ mdoc_ptext(struct roff_man *mdoc, int line, char *buf, int offs)
* Strip trailing tabs in literal context only;
* outside, they affect the next line.
*/
if (MDOC_LITERAL & mdoc->flags)
if (mdoc->flags & ROFF_NOFILL)
continue;
break;
case '\\':
@ -242,8 +227,7 @@ mdoc_ptext(struct roff_man *mdoc, int line, char *buf, int offs)
*end = '\0';
if (ws)
mandoc_msg(MANDOCERR_SPACE_EOL, mdoc->parse,
line, (int)(ws-buf), NULL);
mandoc_msg(MANDOCERR_SPACE_EOL, line, (int)(ws - buf), NULL);
/*
* Blank lines are allowed in no-fill mode
@ -251,7 +235,7 @@ mdoc_ptext(struct roff_man *mdoc, int line, char *buf, int offs)
* but add a single vertical space elsewhere.
*/
if (buf[offs] == '\0' && ! (mdoc->flags & MDOC_LITERAL)) {
if (buf[offs] == '\0' && (mdoc->flags & ROFF_NOFILL) == 0) {
switch (mdoc->last->type) {
case ROFFT_TEXT:
sp = mdoc->last->string;
@ -267,8 +251,7 @@ mdoc_ptext(struct roff_man *mdoc, int line, char *buf, int offs)
default:
break;
}
mandoc_msg(MANDOCERR_FI_BLANK, mdoc->parse,
line, (int)(c - buf), NULL);
mandoc_msg(MANDOCERR_FI_BLANK, line, (int)(c - buf), NULL);
roff_elem_alloc(mdoc, line, offs, ROFF_sp);
mdoc->last->flags |= NODE_VALID | NODE_ENDED;
mdoc->next = ROFF_NEXT_SIBLING;
@ -277,7 +260,7 @@ mdoc_ptext(struct roff_man *mdoc, int line, char *buf, int offs)
roff_word_alloc(mdoc, line, offs, buf+offs);
if (mdoc->flags & MDOC_LITERAL)
if (mdoc->flags & ROFF_NOFILL)
return 1;
/*
@ -308,8 +291,7 @@ mdoc_ptext(struct roff_man *mdoc, int line, char *buf, int offs)
if (*c == ' ')
c++;
if (isupper((unsigned char)(*c)))
mandoc_msg(MANDOCERR_EOS, mdoc->parse,
line, (int)(c - buf), NULL);
mandoc_msg(MANDOCERR_EOS, line, (int)(c - buf), NULL);
}
return 1;
@ -337,8 +319,7 @@ mdoc_pmacro(struct roff_man *mdoc, int ln, char *buf, int offs)
if (sz == 2 || sz == 3)
tok = roffhash_find(mdoc->mdocmac, buf + sv, sz);
if (tok == TOKEN_NONE) {
mandoc_msg(MANDOCERR_MACRO, mdoc->parse,
ln, sv, buf + sv - 1);
mandoc_msg(MANDOCERR_MACRO, ln, sv, "%s", buf + sv - 1);
return 1;
}
@ -368,8 +349,7 @@ mdoc_pmacro(struct roff_man *mdoc, int ln, char *buf, int offs)
*/
if ('\0' == buf[offs] && ' ' == buf[offs - 1])
mandoc_msg(MANDOCERR_SPACE_EOL, mdoc->parse,
ln, offs - 1, NULL);
mandoc_msg(MANDOCERR_SPACE_EOL, ln, offs - 1, NULL);
/*
* If an initial macro or a list invocation, divert directly
@ -378,7 +358,7 @@ mdoc_pmacro(struct roff_man *mdoc, int ln, char *buf, int offs)
n = mdoc->last;
if (n == NULL || tok == MDOC_It || tok == MDOC_El) {
mdoc_macro(mdoc, tok, ln, sv, &offs, buf);
(*mdoc_macro(tok)->fp)(mdoc, tok, ln, sv, &offs, buf);
return 1;
}
@ -394,13 +374,13 @@ mdoc_pmacro(struct roff_man *mdoc, int ln, char *buf, int offs)
(n->parent != NULL && n->parent->tok == MDOC_Bl &&
n->parent->norm->Bl.type == LIST_column)) {
mdoc->flags |= MDOC_FREECOL;
mdoc_macro(mdoc, MDOC_It, ln, sv, &sv, buf);
(*mdoc_macro(MDOC_It)->fp)(mdoc, MDOC_It, ln, sv, &sv, buf);
return 1;
}
/* Normal processing of a macro. */
mdoc_macro(mdoc, tok, ln, sv, &offs, buf);
(*mdoc_macro(tok)->fp)(mdoc, tok, ln, sv, &offs, buf);
/* In quick mode (for mandocdb), abort after the NAME section. */
@ -448,12 +428,3 @@ mdoc_isdelim(const char *p)
return DELIM_NONE;
}
void
mdoc_validate(struct roff_man *mdoc)
{
mdoc->last = mdoc->first;
mdoc_node_validate(mdoc);
mdoc_state_reset(mdoc);
}

View File

@ -1,4 +1,4 @@
/* $Id: mdoc.h,v 1.145 2017/04/24 23:06:18 schwarze Exp $ */
/* $Id: mdoc.h,v 1.146 2018/12/30 00:49:55 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
@ -16,6 +16,9 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
struct roff_node;
struct roff_man;
enum mdocargt {
MDOC_Split, /* -split */
MDOC_Nosplit, /* -nospli */

Some files were not shown because too many files have changed in this diff Show More