From 92395e9c3fc84f2c1861970394d687dfafe3f69c Mon Sep 17 00:00:00 2001 From: Lionel Sambuc Date: Tue, 8 Oct 2013 18:05:29 +0200 Subject: [PATCH] external/bsd/mdocml: Update Change-Id: I17b54e52e8322676d83ed4386f586f8ef3029f72 --- distrib/sets/lists/minix/mi | 902 ++++---- external/bsd/mdocml/Makefile.inc | 7 +- external/bsd/mdocml/bin/mandoc/Makefile | 22 +- external/bsd/mdocml/dist/Makefile | 823 +++++--- external/bsd/mdocml/dist/apropos.1 | 312 +++ external/bsd/mdocml/dist/apropos.c | 157 ++ external/bsd/mdocml/dist/apropos_db.c | 899 ++++++++ external/bsd/mdocml/dist/apropos_db.h | 59 + external/bsd/mdocml/dist/arch.c | 3 +- external/bsd/mdocml/dist/arch.in | 57 +- external/bsd/mdocml/dist/att.c | 3 +- external/bsd/mdocml/dist/att.in | 31 +- external/bsd/mdocml/dist/catman.8 | 111 + external/bsd/mdocml/dist/catman.c | 511 +++++ external/bsd/mdocml/dist/cgi.c | 1210 +++++++++++ external/bsd/mdocml/dist/chars.c | 176 +- external/bsd/mdocml/dist/chars.h | 36 - external/bsd/mdocml/dist/chars.in | 70 +- external/bsd/mdocml/dist/compat_fgetln.c | 93 + external/bsd/mdocml/dist/compat_getsubopt.c | 104 + .../dist/{compat.c => compat_strlcat.c} | 50 +- external/bsd/mdocml/dist/compat_strlcpy.c | 63 + external/bsd/mdocml/dist/config.h.post | 17 + external/bsd/mdocml/dist/config.h.pre | 2 + external/bsd/mdocml/dist/demandoc.1 | 109 + external/bsd/mdocml/dist/demandoc.c | 257 +++ external/bsd/mdocml/dist/eqn.7 | 280 +++ external/bsd/mdocml/dist/eqn.c | 949 +++++++++ external/bsd/mdocml/dist/eqn_html.c | 81 + external/bsd/mdocml/dist/eqn_term.c | 76 + external/bsd/mdocml/dist/example.style.css | 244 +-- external/bsd/mdocml/dist/external.png.uu | 2 +- external/bsd/mdocml/dist/html.c | 427 ++-- external/bsd/mdocml/dist/html.h | 37 +- external/bsd/mdocml/dist/lib.c | 3 +- external/bsd/mdocml/dist/lib.in | 12 +- external/bsd/mdocml/dist/libman.h | 27 +- external/bsd/mdocml/dist/libmandoc.h | 82 +- external/bsd/mdocml/dist/libmdoc.h | 66 +- external/bsd/mdocml/dist/libroff.h | 40 +- external/bsd/mdocml/dist/main.c | 851 +------- external/bsd/mdocml/dist/main.h | 9 +- external/bsd/mdocml/dist/man-cgi.css | 13 + external/bsd/mdocml/dist/man.3 | 272 --- external/bsd/mdocml/dist/man.7 | 690 +++---- external/bsd/mdocml/dist/man.c | 240 ++- external/bsd/mdocml/dist/man.cgi.7 | 123 ++ external/bsd/mdocml/dist/man.h | 41 +- external/bsd/mdocml/dist/man_hash.c | 13 +- external/bsd/mdocml/dist/man_html.c | 368 ++-- external/bsd/mdocml/dist/man_macro.c | 127 +- external/bsd/mdocml/dist/man_term.c | 390 ++-- external/bsd/mdocml/dist/man_validate.c | 309 ++- external/bsd/mdocml/dist/mandoc | Bin 725594 -> 0 bytes external/bsd/mdocml/dist/mandoc.1 | 158 +- external/bsd/mdocml/dist/mandoc.3 | 600 ++++++ external/bsd/mdocml/dist/mandoc.c | 676 ++++-- external/bsd/mdocml/dist/mandoc.h | 207 +- external/bsd/mdocml/dist/mandoc_char.7 | 357 +++- external/bsd/mdocml/dist/mandocdb.8 | 293 +++ external/bsd/mdocml/dist/mandocdb.c | 1834 +++++++++++++++++ external/bsd/mdocml/dist/mandocdb.h | 62 + external/bsd/mdocml/dist/manpath.c | 225 ++ .../bsd/mdocml/dist/{man_argv.c => manpath.h} | 42 +- external/bsd/mdocml/dist/mdoc.3 | 348 ---- external/bsd/mdocml/dist/mdoc.7 | 1797 +++++++++------- external/bsd/mdocml/dist/mdoc.c | 281 ++- external/bsd/mdocml/dist/mdoc.h | 210 +- external/bsd/mdocml/dist/mdoc_argv.c | 720 +++---- external/bsd/mdocml/dist/mdoc_hash.c | 17 +- external/bsd/mdocml/dist/mdoc_html.c | 533 +++-- external/bsd/mdocml/dist/mdoc_macro.c | 180 +- external/bsd/mdocml/dist/mdoc_man.c | 637 ++++++ external/bsd/mdocml/dist/mdoc_strings.c | 219 -- external/bsd/mdocml/dist/mdoc_term.c | 319 +-- external/bsd/mdocml/dist/mdoc_validate.c | 435 ++-- external/bsd/mdocml/dist/msec.c | 6 +- external/bsd/mdocml/dist/msec.in | 18 +- external/bsd/mdocml/dist/out.c | 311 +-- external/bsd/mdocml/dist/out.h | 69 +- external/bsd/mdocml/dist/preconv.1 | 158 ++ external/bsd/mdocml/dist/preconv.c | 528 +++++ external/bsd/mdocml/dist/predefs.in | 65 + external/bsd/mdocml/dist/read.c | 846 ++++++++ external/bsd/mdocml/dist/roff.3 | 177 -- external/bsd/mdocml/dist/roff.7 | 488 ++++- external/bsd/mdocml/dist/roff.c | 998 ++++++--- external/bsd/mdocml/dist/roff.h | 45 - external/bsd/mdocml/dist/st.c | 3 +- external/bsd/mdocml/dist/st.in | 52 +- external/bsd/mdocml/dist/tbl.7 | 74 +- external/bsd/mdocml/dist/tbl.c | 42 +- external/bsd/mdocml/dist/tbl_data.c | 122 +- external/bsd/mdocml/dist/tbl_html.c | 105 +- external/bsd/mdocml/dist/tbl_layout.c | 100 +- external/bsd/mdocml/dist/tbl_opts.c | 34 +- external/bsd/mdocml/dist/tbl_term.c | 257 +-- external/bsd/mdocml/dist/term.c | 426 ++-- external/bsd/mdocml/dist/term.h | 58 +- external/bsd/mdocml/dist/term_ascii.c | 154 +- external/bsd/mdocml/dist/term_ps.c | 398 ++-- external/bsd/mdocml/dist/test-fgetln.c | 11 + external/bsd/mdocml/dist/test-getsubopt.c | 12 + external/bsd/mdocml/dist/test-mmap.c | 10 + external/bsd/mdocml/dist/test-strptime.c | 13 + external/bsd/mdocml/dist/tree.c | 104 +- external/bsd/mdocml/dist/vol.c | 3 +- external/bsd/mdocml/dist/whatis.1 | 172 ++ external/bsd/mdocml/lib/Makefile | 4 +- external/bsd/mdocml/lib/libman/Makefile | 10 - external/bsd/mdocml/lib/libmandoc/Makefile | 13 + external/bsd/mdocml/lib/libmdoc/Makefile | 13 - external/bsd/mdocml/lib/libroff/Makefile | 11 - external/bsd/mdocml/man/Makefile | 13 +- releasetools/nbsd_ports | 2 +- 115 files changed, 19705 insertions(+), 8226 deletions(-) create mode 100644 external/bsd/mdocml/dist/apropos.1 create mode 100644 external/bsd/mdocml/dist/apropos.c create mode 100644 external/bsd/mdocml/dist/apropos_db.c create mode 100644 external/bsd/mdocml/dist/apropos_db.h create mode 100644 external/bsd/mdocml/dist/catman.8 create mode 100644 external/bsd/mdocml/dist/catman.c create mode 100644 external/bsd/mdocml/dist/cgi.c delete mode 100644 external/bsd/mdocml/dist/chars.h create mode 100644 external/bsd/mdocml/dist/compat_fgetln.c create mode 100644 external/bsd/mdocml/dist/compat_getsubopt.c rename external/bsd/mdocml/dist/{compat.c => compat_strlcat.c} (70%) create mode 100644 external/bsd/mdocml/dist/compat_strlcpy.c create mode 100644 external/bsd/mdocml/dist/demandoc.1 create mode 100644 external/bsd/mdocml/dist/demandoc.c create mode 100644 external/bsd/mdocml/dist/eqn.7 create mode 100644 external/bsd/mdocml/dist/eqn.c create mode 100644 external/bsd/mdocml/dist/eqn_html.c create mode 100644 external/bsd/mdocml/dist/eqn_term.c create mode 100644 external/bsd/mdocml/dist/man-cgi.css delete mode 100644 external/bsd/mdocml/dist/man.3 create mode 100644 external/bsd/mdocml/dist/man.cgi.7 delete mode 100755 external/bsd/mdocml/dist/mandoc create mode 100644 external/bsd/mdocml/dist/mandoc.3 create mode 100644 external/bsd/mdocml/dist/mandocdb.8 create mode 100644 external/bsd/mdocml/dist/mandocdb.c create mode 100644 external/bsd/mdocml/dist/mandocdb.h create mode 100644 external/bsd/mdocml/dist/manpath.c rename external/bsd/mdocml/dist/{man_argv.c => manpath.h} (60%) delete mode 100644 external/bsd/mdocml/dist/mdoc.3 create mode 100644 external/bsd/mdocml/dist/mdoc_man.c delete mode 100644 external/bsd/mdocml/dist/mdoc_strings.c create mode 100644 external/bsd/mdocml/dist/preconv.1 create mode 100644 external/bsd/mdocml/dist/preconv.c create mode 100644 external/bsd/mdocml/dist/predefs.in create mode 100644 external/bsd/mdocml/dist/read.c delete mode 100644 external/bsd/mdocml/dist/roff.3 delete mode 100644 external/bsd/mdocml/dist/roff.h create mode 100644 external/bsd/mdocml/dist/test-fgetln.c create mode 100644 external/bsd/mdocml/dist/test-getsubopt.c create mode 100644 external/bsd/mdocml/dist/test-mmap.c create mode 100644 external/bsd/mdocml/dist/test-strptime.c create mode 100644 external/bsd/mdocml/dist/whatis.1 delete mode 100644 external/bsd/mdocml/lib/libman/Makefile create mode 100644 external/bsd/mdocml/lib/libmandoc/Makefile delete mode 100644 external/bsd/mdocml/lib/libmdoc/Makefile delete mode 100644 external/bsd/mdocml/lib/libroff/Makefile diff --git a/distrib/sets/lists/minix/mi b/distrib/sets/lists/minix/mi index 0e5786fff..4f7793b7d 100644 --- a/distrib/sets/lists/minix/mi +++ b/distrib/sets/lists/minix/mi @@ -1180,8 +1180,8 @@ ./usr/include/minix/hgfs.h minix-sys ./usr/include/minix/i2cdriver.h minix-sys ./usr/include/minix/i2c.h minix-sys -./usr/include/minix/input.h minix-sys ./usr/include/minix/inputdriver.h minix-sys +./usr/include/minix/input.h minix-sys ./usr/include/minix/ioctl.h minix-sys ./usr/include/minix/ipcconst.h minix-sys ./usr/include/minix/ipc.h minix-sys @@ -2215,8 +2215,8 @@ ./usr/man/man2/FD_ISSET.2 minix-sys ./usr/man/man2/FD_SET.2 minix-sys ./usr/man/man2/fork.2 minix-sys -./usr/man/man2/fstatvfs.2 minix-sys ./usr/man/man2/fstatvfs1.2 minix-sys +./usr/man/man2/fstatvfs.2 minix-sys ./usr/man/man2/getgid.2 minix-sys ./usr/man/man2/getitimer.2 minix-sys ./usr/man/man2/getnucred.2 minix-sys @@ -2268,8 +2268,8 @@ ./usr/man/man2/sigsuspend.2 minix-sys ./usr/man/man2/socket.2 minix-sys ./usr/man/man2/socketpair.2 minix-sys -./usr/man/man2/statvfs.2 minix-sys ./usr/man/man2/statvfs1.2 minix-sys +./usr/man/man2/statvfs.2 minix-sys ./usr/man/man2/svrctl.2 minix-sys ./usr/man/man2/symlink.2 minix-sys ./usr/man/man2/sync.2 minix-sys @@ -2282,7 +2282,7 @@ ./usr/man/man2/utime.2 minix-sys ./usr/man/man2/wait.2 minix-sys ./usr/man/man2/write.2 minix-sys -./usr/man/man3 minix-sys +./usr/man/man3 minix-sys ./usr/man/man3/a64l.3 minix-sys ./usr/man/man3/abort.3 minix-sys ./usr/man/man3/abs.3 minix-sys @@ -2492,9 +2492,9 @@ ./usr/man/man3/atanh.3 minix-sys ./usr/man/man3/atanhf.3 minix-sys ./usr/man/man3/atexit.3 minix-sys -./usr/man/man3/atf-c-api.3 minix-sys atf -./usr/man/man3/atf-c++-api.3 minix-sys atf -./usr/man/man3/atf-sh-api.3 minix-sys atf +./usr/man/man3/atf-c-api.3 minix-sys atf +./usr/man/man3/atf-c++-api.3 minix-sys atf +./usr/man/man3/atf-sh-api.3 minix-sys atf ./usr/man/man3/atof.3 minix-sys ./usr/man/man3/atoi.3 minix-sys ./usr/man/man3/atol.3 minix-sys @@ -3231,24 +3231,24 @@ ./usr/man/man3/getwd.3 minix-sys ./usr/man/man3/getwin.3 minix-sys ./usr/man/man3/getyx.3 minix-sys -./usr/man/man3/gid_from_group.3 minix-sys +./usr/man/man3/gid_from_group.3 minix-sys ./usr/man/man3/glob.3 minix-sys -./usr/man/man3/globfree.3 minix-sys -./usr/man/man3/glob_pattern_p.3 minix-sys +./usr/man/man3/globfree.3 minix-sys +./usr/man/man3/glob_pattern_p.3 minix-sys ./usr/man/man3/gmtime.3 minix-sys -./usr/man/man3/gmtime_r.3 minix-sys -./usr/man/man3/grantpt.3 minix-sys -./usr/man/man3/group_from_gid.3 minix-sys -./usr/man/man3/halfdelay.3 minix-sys -./usr/man/man3/has_colors.3 minix-sys +./usr/man/man3/gmtime_r.3 minix-sys +./usr/man/man3/grantpt.3 minix-sys +./usr/man/man3/group_from_gid.3 minix-sys +./usr/man/man3/halfdelay.3 minix-sys +./usr/man/man3/has_colors.3 minix-sys ./usr/man/man3/hash.3 minix-sys ./usr/man/man3/has_ic.3 minix-sys ./usr/man/man3/has_il.3 minix-sys -./usr/man/man3/hcreate.3 minix-sys -./usr/man/man3/hcreate_r.3 minix-sys -./usr/man/man3/hdestroy.3 minix-sys -./usr/man/man3/hdestroy_r.3 minix-sys -./usr/man/man3/heapsort.3 minix-sys +./usr/man/man3/hcreate.3 minix-sys +./usr/man/man3/hcreate_r.3 minix-sys +./usr/man/man3/hdestroy.3 minix-sys +./usr/man/man3/hdestroy_r.3 minix-sys +./usr/man/man3/heapsort.3 minix-sys ./usr/man/man3/herror.3 minix-sys ./usr/man/man3/hesiod.3 minix-sys obsolete ./usr/man/man3/hesiod_end.3 minix-sys obsolete @@ -3256,131 +3256,131 @@ ./usr/man/man3/hesiod_init.3 minix-sys obsolete ./usr/man/man3/hesiod_resolve.3 minix-sys obsolete ./usr/man/man3/hesiod_to_bind.3 minix-sys obsolete -./usr/man/man3/history.3 minix-sys -./usr/man/man3/history_end.3 minix-sys -./usr/man/man3/history_init.3 minix-sys +./usr/man/man3/history.3 minix-sys +./usr/man/man3/history_end.3 minix-sys +./usr/man/man3/history_init.3 minix-sys ./usr/man/man3/hline.3 minix-sys -./usr/man/man3/hostalias.3 minix-sys -./usr/man/man3/hsearch.3 minix-sys -./usr/man/man3/hsearch_r.3 minix-sys -./usr/man/man3/hstrerror.3 minix-sys +./usr/man/man3/hostalias.3 minix-sys +./usr/man/man3/hsearch.3 minix-sys +./usr/man/man3/hsearch_r.3 minix-sys +./usr/man/man3/hstrerror.3 minix-sys ./usr/man/man3/htonl.3 minix-sys ./usr/man/man3/htons.3 minix-sys -./usr/man/man3/humanize_number.3 minix-sys +./usr/man/man3/humanize_number.3 minix-sys ./usr/man/man3/hypot.3 minix-sys ./usr/man/man3/hypotf.3 minix-sys ./usr/man/man3/iconv.3 minix-sys -./usr/man/man3/iconv_close.3 minix-sys -./usr/man/man3/iconv_open.3 minix-sys +./usr/man/man3/iconv_close.3 minix-sys +./usr/man/man3/iconv_open.3 minix-sys ./usr/man/man3/idcok.3 minix-sys ./usr/man/man3/idlok.3 minix-sys ./usr/man/man3/ieee.3 minix-sys -./usr/man/man3/ieee_test.3 minix-sys -./usr/man/man3/if_freenameindex.3 minix-sys -./usr/man/man3/if_indextoname.3 minix-sys -./usr/man/man3/if_nameindex.3 minix-sys -./usr/man/man3/if_nametoindex.3 minix-sys +./usr/man/man3/ieee_test.3 minix-sys +./usr/man/man3/if_freenameindex.3 minix-sys +./usr/man/man3/if_indextoname.3 minix-sys +./usr/man/man3/if_nameindex.3 minix-sys +./usr/man/man3/if_nametoindex.3 minix-sys ./usr/man/man3/ilogb.3 minix-sys ./usr/man/man3/ilogbf.3 minix-sys -./usr/man/man3/imaxabs.3 minix-sys -./usr/man/man3/imaxdiv.3 minix-sys +./usr/man/man3/imaxabs.3 minix-sys +./usr/man/man3/imaxdiv.3 minix-sys ./usr/man/man3/inch.3 minix-sys -./usr/man/man3/inchnstr.3 minix-sys -./usr/man/man3/inchstr.3 minix-sys +./usr/man/man3/inchnstr.3 minix-sys +./usr/man/man3/inchstr.3 minix-sys ./usr/man/man3/index.3 minix-sys ./usr/man/man3/inet.3 minix-sys -./usr/man/man3/inet6_opt_append.3 minix-sys -./usr/man/man3/inet6_opt_find.3 minix-sys -./usr/man/man3/inet6_opt_finish.3 minix-sys -./usr/man/man3/inet6_opt_get_val.3 minix-sys -./usr/man/man3/inet6_opt_init.3 minix-sys -./usr/man/man3/inet6_option_alloc.3 minix-sys -./usr/man/man3/inet6_option_append.3 minix-sys -./usr/man/man3/inet6_option_find.3 minix-sys -./usr/man/man3/inet6_option_init.3 minix-sys -./usr/man/man3/inet6_option_next.3 minix-sys -./usr/man/man3/inet6_option_space.3 minix-sys -./usr/man/man3/inet6_opt_next.3 minix-sys -./usr/man/man3/inet6_opt_set_val.3 minix-sys -./usr/man/man3/inet6_rth_add.3 minix-sys -./usr/man/man3/inet6_rthdr_add.3 minix-sys -./usr/man/man3/inet6_rthdr_getaddr.3 minix-sys -./usr/man/man3/inet6_rthdr_getflags.3 minix-sys -./usr/man/man3/inet6_rthdr_init.3 minix-sys -./usr/man/man3/inet6_rthdr_lasthop.3 minix-sys -./usr/man/man3/inet6_rthdr_reverse.3 minix-sys -./usr/man/man3/inet6_rthdr_segments.3 minix-sys -./usr/man/man3/inet6_rthdr_space.3 minix-sys -./usr/man/man3/inet6_rth_getaddr.3 minix-sys -./usr/man/man3/inet6_rth_init.3 minix-sys -./usr/man/man3/inet6_rth_reverse.3 minix-sys -./usr/man/man3/inet6_rth_segments.3 minix-sys -./usr/man/man3/inet6_rth_space.3 minix-sys -./usr/man/man3/inet_addr.3 minix-sys -./usr/man/man3/inet_aton.3 minix-sys -./usr/man/man3/inet_lnaof.3 minix-sys -./usr/man/man3/inet_makeaddr.3 minix-sys -./usr/man/man3/inet_net.3 minix-sys -./usr/man/man3/inet_net_ntop.3 minix-sys -./usr/man/man3/inet_netof.3 minix-sys -./usr/man/man3/inet_net_pton.3 minix-sys -./usr/man/man3/inet_network.3 minix-sys -./usr/man/man3/inet_ntoa.3 minix-sys -./usr/man/man3/inet_ntop.3 minix-sys -./usr/man/man3/inet_pton.3 minix-sys -./usr/man/man3/init_color.3 minix-sys -./usr/man/man3/initgroups.3 minix-sys -./usr/man/man3/init_pair.3 minix-sys -./usr/man/man3/initscr.3 minix-sys -./usr/man/man3/initstate.3 minix-sys -./usr/man/man3/innetgr.3 minix-sys +./usr/man/man3/inet6_opt_append.3 minix-sys +./usr/man/man3/inet6_opt_find.3 minix-sys +./usr/man/man3/inet6_opt_finish.3 minix-sys +./usr/man/man3/inet6_opt_get_val.3 minix-sys +./usr/man/man3/inet6_opt_init.3 minix-sys +./usr/man/man3/inet6_option_alloc.3 minix-sys +./usr/man/man3/inet6_option_append.3 minix-sys +./usr/man/man3/inet6_option_find.3 minix-sys +./usr/man/man3/inet6_option_init.3 minix-sys +./usr/man/man3/inet6_option_next.3 minix-sys +./usr/man/man3/inet6_option_space.3 minix-sys +./usr/man/man3/inet6_opt_next.3 minix-sys +./usr/man/man3/inet6_opt_set_val.3 minix-sys +./usr/man/man3/inet6_rth_add.3 minix-sys +./usr/man/man3/inet6_rthdr_add.3 minix-sys +./usr/man/man3/inet6_rthdr_getaddr.3 minix-sys +./usr/man/man3/inet6_rthdr_getflags.3 minix-sys +./usr/man/man3/inet6_rthdr_init.3 minix-sys +./usr/man/man3/inet6_rthdr_lasthop.3 minix-sys +./usr/man/man3/inet6_rthdr_reverse.3 minix-sys +./usr/man/man3/inet6_rthdr_segments.3 minix-sys +./usr/man/man3/inet6_rthdr_space.3 minix-sys +./usr/man/man3/inet6_rth_getaddr.3 minix-sys +./usr/man/man3/inet6_rth_init.3 minix-sys +./usr/man/man3/inet6_rth_reverse.3 minix-sys +./usr/man/man3/inet6_rth_segments.3 minix-sys +./usr/man/man3/inet6_rth_space.3 minix-sys +./usr/man/man3/inet_addr.3 minix-sys +./usr/man/man3/inet_aton.3 minix-sys +./usr/man/man3/inet_lnaof.3 minix-sys +./usr/man/man3/inet_makeaddr.3 minix-sys +./usr/man/man3/inet_net.3 minix-sys +./usr/man/man3/inet_net_ntop.3 minix-sys +./usr/man/man3/inet_netof.3 minix-sys +./usr/man/man3/inet_net_pton.3 minix-sys +./usr/man/man3/inet_network.3 minix-sys +./usr/man/man3/inet_ntoa.3 minix-sys +./usr/man/man3/inet_ntop.3 minix-sys +./usr/man/man3/inet_pton.3 minix-sys +./usr/man/man3/init_color.3 minix-sys +./usr/man/man3/initgroups.3 minix-sys +./usr/man/man3/init_pair.3 minix-sys +./usr/man/man3/initscr.3 minix-sys +./usr/man/man3/initstate.3 minix-sys +./usr/man/man3/innetgr.3 minix-sys ./usr/man/man3/innstr.3 minix-sys ./usr/man/man3/insch.3 minix-sys -./usr/man/man3/insdelln.3 minix-sys -./usr/man/man3/insertln.3 minix-sys +./usr/man/man3/insdelln.3 minix-sys +./usr/man/man3/insertln.3 minix-sys ./usr/man/man3/insque.3 minix-sys ./usr/man/man3/instr.3 minix-sys -./usr/man/man3/intrflush.3 minix-sys -./usr/man/man3/iruserok.3 minix-sys -./usr/man/man3/iruserok_sa.3 minix-sys -./usr/man/man3/isalnum.3 minix-sys -./usr/man/man3/isalpha.3 minix-sys -./usr/man/man3/isascii.3 minix-sys +./usr/man/man3/intrflush.3 minix-sys +./usr/man/man3/iruserok.3 minix-sys +./usr/man/man3/iruserok_sa.3 minix-sys +./usr/man/man3/isalnum.3 minix-sys +./usr/man/man3/isalpha.3 minix-sys +./usr/man/man3/isascii.3 minix-sys ./usr/man/man3/isatty.3 minix-sys -./usr/man/man3/isblank.3 minix-sys -./usr/man/man3/iscntrl.3 minix-sys -./usr/man/man3/isdigit.3 minix-sys -./usr/man/man3/isendwin.3 minix-sys -./usr/man/man3/isfinite.3 minix-sys -./usr/man/man3/isgraph.3 minix-sys -./usr/man/man3/isgreater.3 minix-sys +./usr/man/man3/isblank.3 minix-sys +./usr/man/man3/iscntrl.3 minix-sys +./usr/man/man3/isdigit.3 minix-sys +./usr/man/man3/isendwin.3 minix-sys +./usr/man/man3/isfinite.3 minix-sys +./usr/man/man3/isgraph.3 minix-sys +./usr/man/man3/isgreater.3 minix-sys ./usr/man/man3/isinf.3 minix-sys ./usr/man/man3/isinff.3 minix-sys -./usr/man/man3/is_linetouched.3 minix-sys -./usr/man/man3/islower.3 minix-sys +./usr/man/man3/is_linetouched.3 minix-sys +./usr/man/man3/islower.3 minix-sys ./usr/man/man3/isnan.3 minix-sys ./usr/man/man3/isnanf.3 minix-sys -./usr/man/man3/isnormal.3 minix-sys -./usr/man/man3/iso_addr.3 minix-sys -./usr/man/man3/isprint.3 minix-sys -./usr/man/man3/ispunct.3 minix-sys -./usr/man/man3/isspace.3 minix-sys -./usr/man/man3/isupper.3 minix-sys -./usr/man/man3/iswalnum.3 minix-sys -./usr/man/man3/iswalpha.3 minix-sys -./usr/man/man3/iswblank.3 minix-sys -./usr/man/man3/iswcntrl.3 minix-sys -./usr/man/man3/iswctype.3 minix-sys -./usr/man/man3/iswdigit.3 minix-sys -./usr/man/man3/iswgraph.3 minix-sys -./usr/man/man3/is_wintouched.3 minix-sys -./usr/man/man3/iswlower.3 minix-sys -./usr/man/man3/iswprint.3 minix-sys -./usr/man/man3/iswpunct.3 minix-sys -./usr/man/man3/iswspace.3 minix-sys -./usr/man/man3/iswupper.3 minix-sys -./usr/man/man3/iswxdigit.3 minix-sys -./usr/man/man3/isxdigit.3 minix-sys +./usr/man/man3/isnormal.3 minix-sys +./usr/man/man3/iso_addr.3 minix-sys +./usr/man/man3/isprint.3 minix-sys +./usr/man/man3/ispunct.3 minix-sys +./usr/man/man3/isspace.3 minix-sys +./usr/man/man3/isupper.3 minix-sys +./usr/man/man3/iswalnum.3 minix-sys +./usr/man/man3/iswalpha.3 minix-sys +./usr/man/man3/iswblank.3 minix-sys +./usr/man/man3/iswcntrl.3 minix-sys +./usr/man/man3/iswctype.3 minix-sys +./usr/man/man3/iswdigit.3 minix-sys +./usr/man/man3/iswgraph.3 minix-sys +./usr/man/man3/is_wintouched.3 minix-sys +./usr/man/man3/iswlower.3 minix-sys +./usr/man/man3/iswprint.3 minix-sys +./usr/man/man3/iswpunct.3 minix-sys +./usr/man/man3/iswspace.3 minix-sys +./usr/man/man3/iswupper.3 minix-sys +./usr/man/man3/iswxdigit.3 minix-sys +./usr/man/man3/isxdigit.3 minix-sys ./usr/man/man3/item_count.3 minix-sys ./usr/man/man3/item_description.3 minix-sys ./usr/man/man3/item_index.3 minix-sys @@ -3398,44 +3398,44 @@ ./usr/man/man3/j0f.3 minix-sys ./usr/man/man3/j1.3 minix-sys ./usr/man/man3/j1f.3 minix-sys -./usr/man/man3/jemalloc.3 minix-sys +./usr/man/man3/jemalloc.3 minix-sys ./usr/man/man3/jn.3 minix-sys ./usr/man/man3/jnf.3 minix-sys -./usr/man/man3/jrand48.3 minix-sys -./usr/man/man3/keyname.3 minix-sys +./usr/man/man3/jrand48.3 minix-sys +./usr/man/man3/keyname.3 minix-sys ./usr/man/man3/keypad.3 minix-sys -./usr/man/man3/killchar.3 minix-sys +./usr/man/man3/killchar.3 minix-sys ./usr/man/man3/killpg.3 minix-sys ./usr/man/man3/l64a.3 minix-sys ./usr/man/man3/l64a_r.3 minix-sys ./usr/man/man3/labs.3 minix-sys -./usr/man/man3/lcong48.3 minix-sys -./usr/man/man3/lcpxattr.3 minix-sys +./usr/man/man3/lcong48.3 minix-sys +./usr/man/man3/lcpxattr.3 minix-sys ./usr/man/man3/ldexp.3 minix-sys ./usr/man/man3/ldiv.3 minix-sys -./usr/man/man3/leaveok.3 minix-sys +./usr/man/man3/leaveok.3 minix-sys ./usr/man/man3/lfind.3 minix-sys ./usr/man/man3/lgamma.3 minix-sys -./usr/man/man3/lgammaf.3 minix-sys -./usr/man/man3/lgammaf_r.3 minix-sys -./usr/man/man3/lgamma_r.3 minix-sys -./usr/man/man3/libarchive.3 minix-sys -./usr/man/man3/libarchive_internals.3 minix-sys -./usr/man/man3/libmagic.3 minix-sys -./usr/man/man3/link_addr.3 minix-sys -./usr/man/man3/linkaddr.3 minix-sys -./usr/man/man3/link_field.3 minix-sys -./usr/man/man3/link_fieldtype.3 minix-sys -./usr/man/man3/link_ntoa.3 minix-sys -./usr/man/man3/linkntoa.3 minix-sys +./usr/man/man3/lgammaf.3 minix-sys +./usr/man/man3/lgammaf_r.3 minix-sys +./usr/man/man3/lgamma_r.3 minix-sys +./usr/man/man3/libarchive.3 minix-sys +./usr/man/man3/libarchive_internals.3 minix-sys +./usr/man/man3/libmagic.3 minix-sys +./usr/man/man3/link_addr.3 minix-sys +./usr/man/man3/link_field.3 minix-sys +./usr/man/man3/link_fieldtype.3 minix-sys +./usr/man/man3/linkaddr.3 minix-sys +./usr/man/man3/link_ntoa.3 minix-sys +./usr/man/man3/linkntoa.3 minix-sys ./usr/man/man3/llabs.3 minix-sys ./usr/man/man3/lldiv.3 minix-sys ./usr/man/man3/llrint.3 minix-sys -./usr/man/man3/llrintf.3 minix-sys -./usr/man/man3/localeconv.3 minix-sys -./usr/man/man3/localtime.3 minix-sys -./usr/man/man3/localtime_r.3 minix-sys -./usr/man/man3/localtime_rz.3 minix-sys +./usr/man/man3/llrintf.3 minix-sys +./usr/man/man3/localeconv.3 minix-sys +./usr/man/man3/localtime.3 minix-sys +./usr/man/man3/localtime_r.3 minix-sys +./usr/man/man3/localtime_rz.3 minix-sys ./usr/man/man3/lockf.3 minix-sys ./usr/man/man3/log10.3 minix-sys ./usr/man/man3/log10f.3 minix-sys @@ -3448,87 +3448,86 @@ ./usr/man/man3/logbf.3 minix-sys ./usr/man/man3/logf.3 minix-sys ./usr/man/man3/login.3 minix-sys -./usr/man/man3/login_cap.3 minix-sys -./usr/man/man3/login_close.3 minix-sys -./usr/man/man3/login_getcapbool.3 minix-sys -./usr/man/man3/login_getcapnum.3 minix-sys -./usr/man/man3/login_getcapsize.3 minix-sys -./usr/man/man3/login_getcapstr.3 minix-sys -./usr/man/man3/login_getcaptime.3 minix-sys -./usr/man/man3/login_getclass.3 minix-sys -./usr/man/man3/login_tty.3 minix-sys +./usr/man/man3/login_cap.3 minix-sys +./usr/man/man3/login_close.3 minix-sys +./usr/man/man3/login_getcapbool.3 minix-sys +./usr/man/man3/login_getcapnum.3 minix-sys +./usr/man/man3/login_getcapsize.3 minix-sys +./usr/man/man3/login_getcapstr.3 minix-sys +./usr/man/man3/login_getcaptime.3 minix-sys +./usr/man/man3/login_getclass.3 minix-sys +./usr/man/man3/login_tty.3 minix-sys ./usr/man/man3/loginx.3 minix-sys ./usr/man/man3/logout.3 minix-sys -./usr/man/man3/logoutx.3 minix-sys -./usr/man/man3/logwtmp.3 minix-sys -./usr/man/man3/logwtmpx.3 minix-sys -./usr/man/man3/_longjmp.3 minix-sys -./usr/man/man3/longjmp.3 minix-sys -./usr/man/man3/longjmperror.3 minix-sys -./usr/man/man3/longname.3 minix-sys -./usr/man/man3/lrand48.3 minix-sys +./usr/man/man3/logoutx.3 minix-sys +./usr/man/man3/logwtmp.3 minix-sys +./usr/man/man3/logwtmpx.3 minix-sys +./usr/man/man3/_longjmp.3 minix-sys +./usr/man/man3/longjmp.3 minix-sys +./usr/man/man3/longjmperror.3 minix-sys +./usr/man/man3/longname.3 minix-sys +./usr/man/man3/lrand48.3 minix-sys ./usr/man/man3/lrint.3 minix-sys ./usr/man/man3/lrintf.3 minix-sys -./usr/man/man3/lsearch.3 minix-sys -./usr/man/man3/_lwp_makecontext.3 minix-sys -./usr/man/man3/magic_buffer.3 minix-sys -./usr/man/man3/magic_check.3 minix-sys -./usr/man/man3/magic_close.3 minix-sys -./usr/man/man3/magic_compile.3 minix-sys -./usr/man/man3/magic_error.3 minix-sys -./usr/man/man3/magic_file.3 minix-sys -./usr/man/man3/magic_load.3 minix-sys -./usr/man/man3/magic_open.3 minix-sys -./usr/man/man3/magic_setflags.3 minix-sys -./usr/man/man3/makecontext.3 minix-sys +./usr/man/man3/lsearch.3 minix-sys +./usr/man/man3/_lwp_makecontext.3 minix-sys +./usr/man/man3/magic_buffer.3 minix-sys +./usr/man/man3/magic_check.3 minix-sys +./usr/man/man3/magic_close.3 minix-sys +./usr/man/man3/magic_compile.3 minix-sys +./usr/man/man3/magic_error.3 minix-sys +./usr/man/man3/magic_file.3 minix-sys +./usr/man/man3/magic_load.3 minix-sys +./usr/man/man3/magic_open.3 minix-sys +./usr/man/man3/magic_setflags.3 minix-sys +./usr/man/man3/makecontext.3 minix-sys ./usr/man/man3/malloc.3 minix-sys -./usr/man/man3/man.3 minix-sys +./usr/man/man3/mandoc.3 minix-sys ./usr/man/man3/math.3 minix-sys ./usr/man/man3/mblen.3 minix-sys ./usr/man/man3/mbrlen.3 minix-sys -./usr/man/man3/mbrtowc.3 minix-sys -./usr/man/man3/mbsinit.3 minix-sys -./usr/man/man3/mbsrtowcs.3 minix-sys -./usr/man/man3/mbstowcs.3 minix-sys +./usr/man/man3/mbrtowc.3 minix-sys +./usr/man/man3/mbsinit.3 minix-sys +./usr/man/man3/mbsrtowcs.3 minix-sys +./usr/man/man3/mbstowcs.3 minix-sys ./usr/man/man3/mbtowc.3 minix-sys ./usr/man/man3/md2.3 minix-sys -./usr/man/man3/MD2Data.3 minix-sys +./usr/man/man3/MD2Data.3 minix-sys ./usr/man/man3/MD2End.3 minix-sys -./usr/man/man3/MD2File.3 minix-sys -./usr/man/man3/MD2FileChunk.3 minix-sys -./usr/man/man3/MD2Final.3 minix-sys -./usr/man/man3/MD2Init.3 minix-sys -./usr/man/man3/MD2Transform.3 minix-sys -./usr/man/man3/MD2Update.3 minix-sys -./usr/man/man3/md4.3 minix-sys -./usr/man/man3/MD4Data.3 minix-sys -./usr/man/man3/MD4End.3 minix-sys -./usr/man/man3/MD4File.3 minix-sys -./usr/man/man3/MD4Final.3 minix-sys -./usr/man/man3/MD4Init.3 minix-sys -./usr/man/man3/MD4Update.3 minix-sys -./usr/man/man3/md5.3 minix-sys -./usr/man/man3/MD5Data.3 minix-sys -./usr/man/man3/MD5End.3 minix-sys -./usr/man/man3/MD5File.3 minix-sys -./usr/man/man3/MD5Final.3 minix-sys -./usr/man/man3/MD5Init.3 minix-sys -./usr/man/man3/MD5Update.3 minix-sys -./usr/man/man3/mdoc.3 minix-sys -./usr/man/man3/membar_consumer.3 minix-sys -./usr/man/man3/membar_enter.3 minix-sys -./usr/man/man3/membar_exit.3 minix-sys -./usr/man/man3/membar_ops.3 minix-sys -./usr/man/man3/membar_producer.3 minix-sys -./usr/man/man3/membar_sync.3 minix-sys -./usr/man/man3/memccpy.3 minix-sys +./usr/man/man3/MD2File.3 minix-sys +./usr/man/man3/MD2FileChunk.3 minix-sys +./usr/man/man3/MD2Final.3 minix-sys +./usr/man/man3/MD2Init.3 minix-sys +./usr/man/man3/MD2Transform.3 minix-sys +./usr/man/man3/MD2Update.3 minix-sys +./usr/man/man3/md4.3 minix-sys +./usr/man/man3/MD4Data.3 minix-sys +./usr/man/man3/MD4End.3 minix-sys +./usr/man/man3/MD4File.3 minix-sys +./usr/man/man3/MD4Final.3 minix-sys +./usr/man/man3/MD4Init.3 minix-sys +./usr/man/man3/MD4Update.3 minix-sys +./usr/man/man3/md5.3 minix-sys +./usr/man/man3/MD5Data.3 minix-sys +./usr/man/man3/MD5End.3 minix-sys +./usr/man/man3/MD5File.3 minix-sys +./usr/man/man3/MD5Final.3 minix-sys +./usr/man/man3/MD5Init.3 minix-sys +./usr/man/man3/MD5Update.3 minix-sys +./usr/man/man3/membar_consumer.3 minix-sys +./usr/man/man3/membar_enter.3 minix-sys +./usr/man/man3/membar_exit.3 minix-sys +./usr/man/man3/membar_ops.3 minix-sys +./usr/man/man3/membar_producer.3 minix-sys +./usr/man/man3/membar_sync.3 minix-sys +./usr/man/man3/memccpy.3 minix-sys ./usr/man/man3/memchr.3 minix-sys ./usr/man/man3/memcmp.3 minix-sys ./usr/man/man3/memcpy.3 minix-sys ./usr/man/man3/memmem.3 minix-sys -./usr/man/man3/memmove.3 minix-sys +./usr/man/man3/memmove.3 minix-sys ./usr/man/man3/memory.3 minix-sys -./usr/man/man3/memrchr.3 minix-sys +./usr/man/man3/memrchr.3 minix-sys ./usr/man/man3/memset.3 minix-sys ./usr/man/man3/menu_attributes.3 minix-sys ./usr/man/man3/menu_back.3 minix-sys @@ -3561,67 +3560,67 @@ ./usr/man/man3/menu_userptr.3 minix-sys ./usr/man/man3/menu_win.3 minix-sys ./usr/man/man3/menus.3 minix-sys -./usr/man/man3/mergesort.3 minix-sys +./usr/man/man3/mergesort.3 minix-sys ./usr/man/man3/meta.3 minix-sys -./usr/man/man3/mi_vector_hash.3 minix-sys -./usr/man/man3/mkdtemp.3 minix-sys -./usr/man/man3/mkstemp.3 minix-sys +./usr/man/man3/mi_vector_hash.3 minix-sys +./usr/man/man3/mkdtemp.3 minix-sys +./usr/man/man3/mkstemp.3 minix-sys ./usr/man/man3/mktemp.3 minix-sys ./usr/man/man3/mktime.3 minix-sys -./usr/man/man3/mktime_z.3 minix-sys +./usr/man/man3/mktime_z.3 minix-sys ./usr/man/man3/modf.3 minix-sys ./usr/man/man3/move.3 minix-sys ./usr/man/man3/move_field.3 minix-sys ./usr/man/man3/mpool.3 minix-sys -./usr/man/man3/mpool_close.3 minix-sys -./usr/man/man3/mpool_filter.3 minix-sys -./usr/man/man3/mpool_get.3 minix-sys -./usr/man/man3/mpool_new.3 minix-sys -./usr/man/man3/mpool_open.3 minix-sys -./usr/man/man3/mpool_put.3 minix-sys -./usr/man/man3/mpool_sync.3 minix-sys -./usr/man/man3/mrand48.3 minix-sys -./usr/man/man3/mvaddch.3 minix-sys -./usr/man/man3/mvaddchnstr.3 minix-sys -./usr/man/man3/mvaddchstr.3 minix-sys -./usr/man/man3/mvaddnstr.3 minix-sys -./usr/man/man3/mvaddstr.3 minix-sys -./usr/man/man3/mvchgat.3 minix-sys +./usr/man/man3/mpool_close.3 minix-sys +./usr/man/man3/mpool_filter.3 minix-sys +./usr/man/man3/mpool_get.3 minix-sys +./usr/man/man3/mpool_new.3 minix-sys +./usr/man/man3/mpool_open.3 minix-sys +./usr/man/man3/mpool_put.3 minix-sys +./usr/man/man3/mpool_sync.3 minix-sys +./usr/man/man3/mrand48.3 minix-sys +./usr/man/man3/mvaddch.3 minix-sys +./usr/man/man3/mvaddchnstr.3 minix-sys +./usr/man/man3/mvaddchstr.3 minix-sys +./usr/man/man3/mvaddnstr.3 minix-sys +./usr/man/man3/mvaddstr.3 minix-sys +./usr/man/man3/mvchgat.3 minix-sys ./usr/man/man3/mvcur.3 minix-sys -./usr/man/man3/mvderwin.3 minix-sys -./usr/man/man3/mvgetch.3 minix-sys -./usr/man/man3/mvgetnstr.3 minix-sys -./usr/man/man3/mvgetstr.3 minix-sys -./usr/man/man3/mvhline.3 minix-sys -./usr/man/man3/mvinchnstr.3 minix-sys -./usr/man/man3/mvinchstr.3 minix-sys -./usr/man/man3/mvinnstr.3 minix-sys -./usr/man/man3/mvinstr.3 minix-sys -./usr/man/man3/mvprintw.3 minix-sys -./usr/man/man3/mvvline.3 minix-sys -./usr/man/man3/mvwaddch.3 minix-sys -./usr/man/man3/mvwaddchnstr.3 minix-sys -./usr/man/man3/mvwaddchstr.3 minix-sys -./usr/man/man3/mvwaddnstr.3 minix-sys -./usr/man/man3/mvwaddstr.3 minix-sys -./usr/man/man3/mvwchgat.3 minix-sys -./usr/man/man3/mvwgetch.3 minix-sys -./usr/man/man3/mvwgetnstr.3 minix-sys -./usr/man/man3/mvwgetstr.3 minix-sys -./usr/man/man3/mvwhline.3 minix-sys +./usr/man/man3/mvderwin.3 minix-sys +./usr/man/man3/mvgetch.3 minix-sys +./usr/man/man3/mvgetnstr.3 minix-sys +./usr/man/man3/mvgetstr.3 minix-sys +./usr/man/man3/mvhline.3 minix-sys +./usr/man/man3/mvinchnstr.3 minix-sys +./usr/man/man3/mvinchstr.3 minix-sys +./usr/man/man3/mvinnstr.3 minix-sys +./usr/man/man3/mvinstr.3 minix-sys +./usr/man/man3/mvprintw.3 minix-sys +./usr/man/man3/mvvline.3 minix-sys +./usr/man/man3/mvwaddch.3 minix-sys +./usr/man/man3/mvwaddchnstr.3 minix-sys +./usr/man/man3/mvwaddchstr.3 minix-sys +./usr/man/man3/mvwaddnstr.3 minix-sys +./usr/man/man3/mvwaddstr.3 minix-sys +./usr/man/man3/mvwchgat.3 minix-sys +./usr/man/man3/mvwgetch.3 minix-sys +./usr/man/man3/mvwgetnstr.3 minix-sys +./usr/man/man3/mvwgetstr.3 minix-sys +./usr/man/man3/mvwhline.3 minix-sys ./usr/man/man3/mvwin.3 minix-sys -./usr/man/man3/mvwinchnstr.3 minix-sys -./usr/man/man3/mvwinchstr.3 minix-sys -./usr/man/man3/mvwinnstr.3 minix-sys -./usr/man/man3/mvwinstr.3 minix-sys -./usr/man/man3/mvwprintw.3 minix-sys -./usr/man/man3/mvwvline.3 minix-sys +./usr/man/man3/mvwinchnstr.3 minix-sys +./usr/man/man3/mvwinchstr.3 minix-sys +./usr/man/man3/mvwinnstr.3 minix-sys +./usr/man/man3/mvwinstr.3 minix-sys +./usr/man/man3/mvwprintw.3 minix-sys +./usr/man/man3/mvwvline.3 minix-sys ./usr/man/man3/nan.3 minix-sys ./usr/man/man3/nanf.3 minix-sys ./usr/man/man3/nanl.3 minix-sys ./usr/man/man3/napms.3 minix-sys ./usr/man/man3/ndbm.3 minix-sys -./usr/man/man3/network.3 minix-sys +./usr/man/man3/network.3 minix-sys ./usr/man/man3/new_field.3 minix-sys ./usr/man/man3/new_fieldtype.3 minix-sys ./usr/man/man3/new_form.3 minix-sys @@ -3629,217 +3628,217 @@ ./usr/man/man3/new_menu.3 minix-sys ./usr/man/man3/new_page.3 minix-sys ./usr/man/man3/newpad.3 minix-sys -./usr/man/man3/newterm.3 minix-sys +./usr/man/man3/newterm.3 minix-sys ./usr/man/man3/newwin.3 minix-sys -./usr/man/man3/nextafter.3 minix-sys -./usr/man/man3/nextafterf.3 minix-sys -./usr/man/man3/nextafterl.3 minix-sys -./usr/man/man3/nexttoward.3 minix-sys +./usr/man/man3/nextafter.3 minix-sys +./usr/man/man3/nextafterf.3 minix-sys +./usr/man/man3/nextafterl.3 minix-sys +./usr/man/man3/nexttoward.3 minix-sys ./usr/man/man3/nftw.3 minix-sys ./usr/man/man3/nice.3 minix-sys ./usr/man/man3/nl.3 minix-sys ./usr/man/man3/nlist.3 minix-sys -./usr/man/man3/nl_langinfo.3 minix-sys -./usr/man/man3/nocbreak.3 minix-sys -./usr/man/man3/nodelay.3 minix-sys +./usr/man/man3/nl_langinfo.3 minix-sys +./usr/man/man3/nocbreak.3 minix-sys +./usr/man/man3/nodelay.3 minix-sys ./usr/man/man3/noecho.3 minix-sys ./usr/man/man3/nonl.3 minix-sys -./usr/man/man3/noqiflush.3 minix-sys +./usr/man/man3/noqiflush.3 minix-sys ./usr/man/man3/noraw.3 minix-sys -./usr/man/man3/notimeout.3 minix-sys -./usr/man/man3/nrand48.3 minix-sys -./usr/man/man3/nsdispatch.3 minix-sys +./usr/man/man3/notimeout.3 minix-sys +./usr/man/man3/nrand48.3 minix-sys +./usr/man/man3/nsdispatch.3 minix-sys ./usr/man/man3/ntoa.3 minix-sys ./usr/man/man3/ntohl.3 minix-sys ./usr/man/man3/ntohs.3 minix-sys -./usr/man/man3/nvis.3 minix-sys -./usr/man/man3/offtime.3 minix-sys -./usr/man/man3/offtime_r.3 minix-sys -./usr/man/man3/opendir.3 minix-sys -./usr/man/man3/opendisk.3 minix-sys -./usr/man/man3/openlog.3 minix-sys -./usr/man/man3/openlog_r.3 minix-sys -./usr/man/man3/openpty.3 minix-sys +./usr/man/man3/nvis.3 minix-sys +./usr/man/man3/offtime.3 minix-sys +./usr/man/man3/offtime_r.3 minix-sys +./usr/man/man3/opendir.3 minix-sys +./usr/man/man3/opendisk.3 minix-sys +./usr/man/man3/openlog.3 minix-sys +./usr/man/man3/openlog_r.3 minix-sys +./usr/man/man3/openpty.3 minix-sys ./usr/man/man3/orcmd.3 minix-sys -./usr/man/man3/orcmd_af.3 minix-sys -./usr/man/man3/overlay.3 minix-sys -./usr/man/man3/overwrite.3 minix-sys -./usr/man/man3/pair_content.3 minix-sys +./usr/man/man3/orcmd_af.3 minix-sys +./usr/man/man3/overlay.3 minix-sys +./usr/man/man3/overwrite.3 minix-sys +./usr/man/man3/pair_content.3 minix-sys ./usr/man/man3/pause.3 minix-sys ./usr/man/man3/pclose.3 minix-sys -./usr/man/man3/pechochar.3 minix-sys +./usr/man/man3/pechochar.3 minix-sys ./usr/man/man3/perror.3 minix-sys -./usr/man/man3/pidfile.3 minix-sys -./usr/man/man3/pidlock.3 minix-sys -./usr/man/man3/pnoutrefresh.3 minix-sys -./usr/man/man3/popcount.3 minix-sys -./usr/man/man3/popcount32.3 minix-sys -./usr/man/man3/popcount64.3 minix-sys -./usr/man/man3/popcountl.3 minix-sys -./usr/man/man3/popcountll.3 minix-sys +./usr/man/man3/pidfile.3 minix-sys +./usr/man/man3/pidlock.3 minix-sys +./usr/man/man3/pnoutrefresh.3 minix-sys +./usr/man/man3/popcount.3 minix-sys +./usr/man/man3/popcount32.3 minix-sys +./usr/man/man3/popcount64.3 minix-sys +./usr/man/man3/popcountl.3 minix-sys +./usr/man/man3/popcountll.3 minix-sys ./usr/man/man3/popen.3 minix-sys ./usr/man/man3/pos_form_cursor.3 minix-sys ./usr/man/man3/pos_menu_cursor.3 minix-sys -./usr/man/man3/posix2time.3 minix-sys -./usr/man/man3/posix2time_z.3 minix-sys -./usr/man/man3/posix_memalign.3 minix-sys -./usr/man/man3/posix_openpt.3 minix-sys -./usr/man/man3/posix_spawn.3 minix-sys -./usr/man/man3/posix_spawnattr_destroy.3 minix-sys -./usr/man/man3/posix_spawnattr_getflags.3 minix-sys -./usr/man/man3/posix_spawnattr_getpgroup.3 minix-sys -./usr/man/man3/posix_spawnattr_getschedparam.3 minix-sys -./usr/man/man3/posix_spawnattr_getschedpolicy.3 minix-sys -./usr/man/man3/posix_spawnattr_getsigdefault.3 minix-sys -./usr/man/man3/posix_spawnattr_getsigmask.3 minix-sys +./usr/man/man3/posix2time.3 minix-sys +./usr/man/man3/posix2time_z.3 minix-sys +./usr/man/man3/posix_memalign.3 minix-sys +./usr/man/man3/posix_openpt.3 minix-sys +./usr/man/man3/posix_spawn.3 minix-sys +./usr/man/man3/posix_spawnattr_destroy.3 minix-sys +./usr/man/man3/posix_spawnattr_getflags.3 minix-sys +./usr/man/man3/posix_spawnattr_getpgroup.3 minix-sys +./usr/man/man3/posix_spawnattr_getschedparam.3 minix-sys +./usr/man/man3/posix_spawnattr_getschedpolicy.3 minix-sys +./usr/man/man3/posix_spawnattr_getsigdefault.3 minix-sys +./usr/man/man3/posix_spawnattr_getsigmask.3 minix-sys ./usr/man/man3/posix_spawnattr_init.3 minix-sys -./usr/man/man3/posix_spawnattr_setflags.3 minix-sys -./usr/man/man3/posix_spawnattr_setpgroup.3 minix-sys -./usr/man/man3/posix_spawnattr_setschedparam.3 minix-sys -./usr/man/man3/posix_spawnattr_setschedpolicy.3 minix-sys -./usr/man/man3/posix_spawnattr_setsigdefault.3 minix-sys -./usr/man/man3/posix_spawnattr_setsigmask.3 minix-sys -./usr/man/man3/posix_spawn_file_actions_addclose.3 minix-sys -./usr/man/man3/posix_spawn_file_actions_adddup2.3 minix-sys -./usr/man/man3/posix_spawn_file_actions_addopen.3 minix-sys -./usr/man/man3/posix_spawn_file_actions_destroy.3 minix-sys -./usr/man/man3/posix_spawn_file_actions_init.3 minix-sys -./usr/man/man3/posix_spawnp.3 minix-sys +./usr/man/man3/posix_spawnattr_setflags.3 minix-sys +./usr/man/man3/posix_spawnattr_setpgroup.3 minix-sys +./usr/man/man3/posix_spawnattr_setschedparam.3 minix-sys +./usr/man/man3/posix_spawnattr_setschedpolicy.3 minix-sys +./usr/man/man3/posix_spawnattr_setsigdefault.3 minix-sys +./usr/man/man3/posix_spawnattr_setsigmask.3 minix-sys +./usr/man/man3/posix_spawn_file_actions_addclose.3 minix-sys +./usr/man/man3/posix_spawn_file_actions_adddup2.3 minix-sys +./usr/man/man3/posix_spawn_file_actions_addopen.3 minix-sys +./usr/man/man3/posix_spawn_file_actions_destroy.3 minix-sys +./usr/man/man3/posix_spawn_file_actions_init.3 minix-sys +./usr/man/man3/posix_spawnp.3 minix-sys ./usr/man/man3/post_form.3 minix-sys ./usr/man/man3/post_menu.3 minix-sys ./usr/man/man3/pow.3 minix-sys ./usr/man/man3/powf.3 minix-sys -./usr/man/man3/p_query.3 minix-sys -./usr/man/man3/prefresh.3 minix-sys +./usr/man/man3/p_query.3 minix-sys +./usr/man/man3/prefresh.3 minix-sys ./usr/man/man3/printf.3 minix-sys ./usr/man/man3/printw.3 minix-sys -./usr/man/man3/prop_array.3 minix-sys -./usr/man/man3/prop_array_add.3 minix-sys -./usr/man/man3/prop_array_capacity.3 minix-sys -./usr/man/man3/prop_array_copy.3 minix-sys -./usr/man/man3/prop_array_copy_mutable.3 minix-sys -./usr/man/man3/prop_array_count.3 minix-sys -./usr/man/man3/prop_array_create.3 minix-sys -./usr/man/man3/prop_array_create_with_capacity.3 minix-sys -./usr/man/man3/prop_array_ensure_capacity.3 minix-sys -./usr/man/man3/prop_array_equals.3 minix-sys -./usr/man/man3/prop_array_externalize.3 minix-sys -./usr/man/man3/prop_array_externalize_to_file.3 minix-sys -./usr/man/man3/prop_array_externalize_to_pref.3 minix-sys -./usr/man/man3/prop_array_get.3 minix-sys -./usr/man/man3/prop_array_get_bool.3 minix-sys -./usr/man/man3/prop_array_get_cstring.3 minix-sys -./usr/man/man3/prop_array_get_cstring_nocopy.3 minix-sys -./usr/man/man3/prop_array_get_int16.3 minix-sys -./usr/man/man3/prop_array_get_int32.3 minix-sys -./usr/man/man3/prop_array_get_int64.3 minix-sys -./usr/man/man3/prop_array_get_int8.3 minix-sys -./usr/man/man3/prop_array_get_uint16.3 minix-sys -./usr/man/man3/prop_array_get_uint32.3 minix-sys -./usr/man/man3/prop_array_get_uint64.3 minix-sys -./usr/man/man3/prop_array_get_uint8.3 minix-sys -./usr/man/man3/prop_array_internalize.3 minix-sys -./usr/man/man3/prop_array_internalize_from_file.3 minix-sys -./usr/man/man3/prop_array_internalize_from_pref.3 minix-sys -./usr/man/man3/prop_array_iterator.3 minix-sys -./usr/man/man3/prop_array_make_immutable.3 minix-sys -./usr/man/man3/prop_array_mutable.3 minix-sys -./usr/man/man3/prop_array_recv_ioctl.3 minix-sys -./usr/man/man3/prop_array_recv_syscall.3 minix-sys -./usr/man/man3/prop_array_remove.3 minix-sys -./usr/man/man3/prop_array_send_ioctl.3 minix-sys -./usr/man/man3/prop_array_send_syscall.3 minix-sys -./usr/man/man3/prop_array_set.3 minix-sys -./usr/man/man3/prop_array_set_bool.3 minix-sys -./usr/man/man3/prop_array_set_cstring.3 minix-sys -./usr/man/man3/prop_array_set_cstring_nocopy.3 minix-sys -./usr/man/man3/prop_array_set_int16.3 minix-sys -./usr/man/man3/prop_array_set_int32.3 minix-sys -./usr/man/man3/prop_array_set_int64.3 minix-sys -./usr/man/man3/prop_array_set_int8.3 minix-sys -./usr/man/man3/prop_array_set_uint16.3 minix-sys -./usr/man/man3/prop_array_set_uint32.3 minix-sys -./usr/man/man3/prop_array_set_uint64.3 minix-sys -./usr/man/man3/prop_array_set_uint8.3 minix-sys -./usr/man/man3/prop_array_util.3 minix-sys -./usr/man/man3/prop_bool.3 minix-sys -./usr/man/man3/prop_bool_copy.3 minix-sys -./usr/man/man3/prop_bool_create.3 minix-sys -./usr/man/man3/prop_bool_true.3 minix-sys -./usr/man/man3/prop_data.3 minix-sys -./usr/man/man3/prop_data_copy.3 minix-sys -./usr/man/man3/prop_data_create_data.3 minix-sys -./usr/man/man3/prop_data_create_data_nocopy.3 minix-sys -./usr/man/man3/prop_data_data.3 minix-sys -./usr/man/man3/prop_data_data_nocopy.3 minix-sys -./usr/man/man3/prop_data_equals.3 minix-sys -./usr/man/man3/prop_data_equals_data.3 minix-sys -./usr/man/man3/prop_data_size.3 minix-sys -./usr/man/man3/prop_dictionary.3 minix-sys -./usr/man/man3/prop_dictionary_all_keys.3 minix-sys -./usr/man/man3/prop_dictionary_capacity.3 minix-sys -./usr/man/man3/prop_dictionary_copy.3 minix-sys -./usr/man/man3/prop_dictionary_copy_mutable.3 minix-sys -./usr/man/man3/prop_dictionary_count.3 minix-sys -./usr/man/man3/prop_dictionary_create.3 minix-sys -./usr/man/man3/prop_dictionary_create_with_capacity.3 minix-sys -./usr/man/man3/prop_dictionary_ensure_capacity.3 minix-sys -./usr/man/man3/prop_dictionary_equals.3 minix-sys -./usr/man/man3/prop_dictionary_externalize.3 minix-sys -./usr/man/man3/prop_dictionary_externalize_to_file.3 minix-sys -./usr/man/man3/prop_dictionary_externalize_to_pref.3 minix-sys -./usr/man/man3/prop_dictionary_get.3 minix-sys -./usr/man/man3/prop_dictionary_get_bool.3 minix-sys -./usr/man/man3/prop_dictionary_get_cstring.3 minix-sys -./usr/man/man3/prop_dictionary_get_cstring_nocopy.3 minix-sys -./usr/man/man3/prop_dictionary_get_int16.3 minix-sys -./usr/man/man3/prop_dictionary_get_int32.3 minix-sys -./usr/man/man3/prop_dictionary_get_int64.3 minix-sys -./usr/man/man3/prop_dictionary_get_int8.3 minix-sys -./usr/man/man3/prop_dictionary_get_keysym.3 minix-sys -./usr/man/man3/prop_dictionary_get_uint16.3 minix-sys -./usr/man/man3/prop_dictionary_get_uint32.3 minix-sys -./usr/man/man3/prop_dictionary_get_uint64.3 minix-sys -./usr/man/man3/prop_dictionary_get_uint8.3 minix-sys -./usr/man/man3/prop_dictionary_ingest.3 minix-sys -./usr/man/man3/prop_dictionary_internalize.3 minix-sys -./usr/man/man3/prop_dictionary_internalize_from_file.3 minix-sys -./usr/man/man3/prop_dictionary_internalize_from_pref.3 minix-sys -./usr/man/man3/prop_dictionary_iterator.3 minix-sys -./usr/man/man3/prop_dictionary_keysym_cstring_nocopy.3 minix-sys -./usr/man/man3/prop_dictionary_keysym_equals.3 minix-sys -./usr/man/man3/prop_dictionary_make_immutable.3 minix-sys -./usr/man/man3/prop_dictionary_mutable.3 minix-sys -./usr/man/man3/prop_dictionary_recv_ioctl.3 minix-sys -./usr/man/man3/prop_dictionary_recv_syscall.3 minix-sys -./usr/man/man3/prop_dictionary_remove.3 minix-sys -./usr/man/man3/prop_dictionary_remove_keysym.3 minix-sys -./usr/man/man3/prop_dictionary_send_ioctl.3 minix-sys -./usr/man/man3/prop_dictionary_sendrecv_ioctl.3 minix-sys -./usr/man/man3/prop_dictionary_send_syscall.3 minix-sys -./usr/man/man3/prop_dictionary_set.3 minix-sys -./usr/man/man3/prop_dictionary_set_bool.3 minix-sys -./usr/man/man3/prop_dictionary_set_cstring.3 minix-sys -./usr/man/man3/prop_dictionary_set_cstring_nocopy.3 minix-sys -./usr/man/man3/prop_dictionary_set_int16.3 minix-sys -./usr/man/man3/prop_dictionary_set_int32.3 minix-sys -./usr/man/man3/prop_dictionary_set_int64.3 minix-sys -./usr/man/man3/prop_dictionary_set_int8.3 minix-sys -./usr/man/man3/prop_dictionary_set_keysym.3 minix-sys -./usr/man/man3/prop_dictionary_set_uint16.3 minix-sys -./usr/man/man3/prop_dictionary_set_uint32.3 minix-sys -./usr/man/man3/prop_dictionary_set_uint64.3 minix-sys -./usr/man/man3/prop_dictionary_set_uint8.3 minix-sys -./usr/man/man3/prop_dictionary_util.3 minix-sys -./usr/man/man3/prop_ingest.3 minix-sys -./usr/man/man3/prop_ingest_context_alloc.3 minix-sys -./usr/man/man3/prop_ingest_context_error.3 minix-sys -./usr/man/man3/prop_ingest_context_free.3 minix-sys -./usr/man/man3/prop_ingest_context_key.3 minix-sys -./usr/man/man3/prop_ingest_context_private.3 minix-sys -./usr/man/man3/prop_ingest_context_type.3 minix-sys -./usr/man/man3/proplib.3 minix-sys -./usr/man/man3/prop_number.3 minix-sys +./usr/man/man3/prop_array.3 minix-sys +./usr/man/man3/prop_array_add.3 minix-sys +./usr/man/man3/prop_array_capacity.3 minix-sys +./usr/man/man3/prop_array_copy.3 minix-sys +./usr/man/man3/prop_array_copy_mutable.3 minix-sys +./usr/man/man3/prop_array_count.3 minix-sys +./usr/man/man3/prop_array_create.3 minix-sys +./usr/man/man3/prop_array_create_with_capacity.3 minix-sys +./usr/man/man3/prop_array_ensure_capacity.3 minix-sys +./usr/man/man3/prop_array_equals.3 minix-sys +./usr/man/man3/prop_array_externalize.3 minix-sys +./usr/man/man3/prop_array_externalize_to_file.3 minix-sys +./usr/man/man3/prop_array_externalize_to_pref.3 minix-sys +./usr/man/man3/prop_array_get.3 minix-sys +./usr/man/man3/prop_array_get_bool.3 minix-sys +./usr/man/man3/prop_array_get_cstring.3 minix-sys +./usr/man/man3/prop_array_get_cstring_nocopy.3 minix-sys +./usr/man/man3/prop_array_get_int16.3 minix-sys +./usr/man/man3/prop_array_get_int32.3 minix-sys +./usr/man/man3/prop_array_get_int64.3 minix-sys +./usr/man/man3/prop_array_get_int8.3 minix-sys +./usr/man/man3/prop_array_get_uint16.3 minix-sys +./usr/man/man3/prop_array_get_uint32.3 minix-sys +./usr/man/man3/prop_array_get_uint64.3 minix-sys +./usr/man/man3/prop_array_get_uint8.3 minix-sys +./usr/man/man3/prop_array_internalize.3 minix-sys +./usr/man/man3/prop_array_internalize_from_file.3 minix-sys +./usr/man/man3/prop_array_internalize_from_pref.3 minix-sys +./usr/man/man3/prop_array_iterator.3 minix-sys +./usr/man/man3/prop_array_make_immutable.3 minix-sys +./usr/man/man3/prop_array_mutable.3 minix-sys +./usr/man/man3/prop_array_recv_ioctl.3 minix-sys +./usr/man/man3/prop_array_recv_syscall.3 minix-sys +./usr/man/man3/prop_array_remove.3 minix-sys +./usr/man/man3/prop_array_send_ioctl.3 minix-sys +./usr/man/man3/prop_array_send_syscall.3 minix-sys +./usr/man/man3/prop_array_set.3 minix-sys +./usr/man/man3/prop_array_set_bool.3 minix-sys +./usr/man/man3/prop_array_set_cstring.3 minix-sys +./usr/man/man3/prop_array_set_cstring_nocopy.3 minix-sys +./usr/man/man3/prop_array_set_int16.3 minix-sys +./usr/man/man3/prop_array_set_int32.3 minix-sys +./usr/man/man3/prop_array_set_int64.3 minix-sys +./usr/man/man3/prop_array_set_int8.3 minix-sys +./usr/man/man3/prop_array_set_uint16.3 minix-sys +./usr/man/man3/prop_array_set_uint32.3 minix-sys +./usr/man/man3/prop_array_set_uint64.3 minix-sys +./usr/man/man3/prop_array_set_uint8.3 minix-sys +./usr/man/man3/prop_array_util.3 minix-sys +./usr/man/man3/prop_bool.3 minix-sys +./usr/man/man3/prop_bool_copy.3 minix-sys +./usr/man/man3/prop_bool_create.3 minix-sys +./usr/man/man3/prop_bool_true.3 minix-sys +./usr/man/man3/prop_data.3 minix-sys +./usr/man/man3/prop_data_copy.3 minix-sys +./usr/man/man3/prop_data_create_data.3 minix-sys +./usr/man/man3/prop_data_create_data_nocopy.3 minix-sys +./usr/man/man3/prop_data_data.3 minix-sys +./usr/man/man3/prop_data_data_nocopy.3 minix-sys +./usr/man/man3/prop_data_equals.3 minix-sys +./usr/man/man3/prop_data_equals_data.3 minix-sys +./usr/man/man3/prop_data_size.3 minix-sys +./usr/man/man3/prop_dictionary.3 minix-sys +./usr/man/man3/prop_dictionary_all_keys.3 minix-sys +./usr/man/man3/prop_dictionary_capacity.3 minix-sys +./usr/man/man3/prop_dictionary_copy.3 minix-sys +./usr/man/man3/prop_dictionary_copy_mutable.3 minix-sys +./usr/man/man3/prop_dictionary_count.3 minix-sys +./usr/man/man3/prop_dictionary_create.3 minix-sys +./usr/man/man3/prop_dictionary_create_with_capacity.3 minix-sys +./usr/man/man3/prop_dictionary_ensure_capacity.3 minix-sys +./usr/man/man3/prop_dictionary_equals.3 minix-sys +./usr/man/man3/prop_dictionary_externalize.3 minix-sys +./usr/man/man3/prop_dictionary_externalize_to_file.3 minix-sys +./usr/man/man3/prop_dictionary_externalize_to_pref.3 minix-sys +./usr/man/man3/prop_dictionary_get.3 minix-sys +./usr/man/man3/prop_dictionary_get_bool.3 minix-sys +./usr/man/man3/prop_dictionary_get_cstring.3 minix-sys +./usr/man/man3/prop_dictionary_get_cstring_nocopy.3 minix-sys +./usr/man/man3/prop_dictionary_get_int16.3 minix-sys +./usr/man/man3/prop_dictionary_get_int32.3 minix-sys +./usr/man/man3/prop_dictionary_get_int64.3 minix-sys +./usr/man/man3/prop_dictionary_get_int8.3 minix-sys +./usr/man/man3/prop_dictionary_get_keysym.3 minix-sys +./usr/man/man3/prop_dictionary_get_uint16.3 minix-sys +./usr/man/man3/prop_dictionary_get_uint32.3 minix-sys +./usr/man/man3/prop_dictionary_get_uint64.3 minix-sys +./usr/man/man3/prop_dictionary_get_uint8.3 minix-sys +./usr/man/man3/prop_dictionary_ingest.3 minix-sys +./usr/man/man3/prop_dictionary_internalize.3 minix-sys +./usr/man/man3/prop_dictionary_internalize_from_file.3 minix-sys +./usr/man/man3/prop_dictionary_internalize_from_pref.3 minix-sys +./usr/man/man3/prop_dictionary_iterator.3 minix-sys +./usr/man/man3/prop_dictionary_keysym_cstring_nocopy.3 minix-sys +./usr/man/man3/prop_dictionary_keysym_equals.3 minix-sys +./usr/man/man3/prop_dictionary_make_immutable.3 minix-sys +./usr/man/man3/prop_dictionary_mutable.3 minix-sys +./usr/man/man3/prop_dictionary_recv_ioctl.3 minix-sys +./usr/man/man3/prop_dictionary_recv_syscall.3 minix-sys +./usr/man/man3/prop_dictionary_remove.3 minix-sys +./usr/man/man3/prop_dictionary_remove_keysym.3 minix-sys +./usr/man/man3/prop_dictionary_send_ioctl.3 minix-sys +./usr/man/man3/prop_dictionary_sendrecv_ioctl.3 minix-sys +./usr/man/man3/prop_dictionary_send_syscall.3 minix-sys +./usr/man/man3/prop_dictionary_set.3 minix-sys +./usr/man/man3/prop_dictionary_set_bool.3 minix-sys +./usr/man/man3/prop_dictionary_set_cstring.3 minix-sys +./usr/man/man3/prop_dictionary_set_cstring_nocopy.3 minix-sys +./usr/man/man3/prop_dictionary_set_int16.3 minix-sys +./usr/man/man3/prop_dictionary_set_int32.3 minix-sys +./usr/man/man3/prop_dictionary_set_int64.3 minix-sys +./usr/man/man3/prop_dictionary_set_int8.3 minix-sys +./usr/man/man3/prop_dictionary_set_keysym.3 minix-sys +./usr/man/man3/prop_dictionary_set_uint16.3 minix-sys +./usr/man/man3/prop_dictionary_set_uint32.3 minix-sys +./usr/man/man3/prop_dictionary_set_uint64.3 minix-sys +./usr/man/man3/prop_dictionary_set_uint8.3 minix-sys +./usr/man/man3/prop_dictionary_util.3 minix-sys +./usr/man/man3/prop_ingest.3 minix-sys +./usr/man/man3/prop_ingest_context_alloc.3 minix-sys +./usr/man/man3/prop_ingest_context_error.3 minix-sys +./usr/man/man3/prop_ingest_context_free.3 minix-sys +./usr/man/man3/prop_ingest_context_key.3 minix-sys +./usr/man/man3/prop_ingest_context_private.3 minix-sys +./usr/man/man3/prop_ingest_context_type.3 minix-sys +./usr/man/man3/proplib.3 minix-sys +./usr/man/man3/prop_number.3 minix-sys ./usr/man/man3/prop_number_copy.3 minix-sys ./usr/man/man3/prop_number_create_integer.3 minix-sys ./usr/man/man3/prop_number_create_unsigned_integer.3 minix-sys @@ -4617,6 +4616,7 @@ ./usr/man/man7/kyua-test-filters.7 minix-sys kyua ./usr/man/man7/man.7 minix-sys ./usr/man/man7/mandoc_char.7 minix-sys +./usr/man/man7/mandoc_eqn.7 minix-sys ./usr/man/man7/mandoc_man.7 minix-sys ./usr/man/man7/mandoc_mdoc.7 minix-sys ./usr/man/man7/mandoc_roff.7 minix-sys @@ -4768,8 +4768,8 @@ ./usr/sbin/vipw minix-sys ./usr/sbin/vm minix-sys ./usr/sbin/vnconfig minix-sys -./usr/sbin/vndconfig minix-sys ./usr/sbin/vnd minix-sys +./usr/sbin/vndconfig minix-sys ./usr/sbin/zic minix-sys ./usr/share minix-sys ./usr/share/atf minix-sys atf @@ -5575,6 +5575,12 @@ ./usr/tests/lib/libpthread/dlopen minix-sys atf ./usr/tests/libexec/Atffile minix-sys atf ./usr/tests/minix-posix minix-sys +./usr/tests/minix-posix/blocktest minix-sys +./usr/tests/minix-posix/blocktest/blocktest minix-sys +./usr/tests/minix-posix/blocktest/README minix-sys +./usr/tests/minix-posix/blocktest/support.sh minix-sys +./usr/tests/minix-posix/blocktest/system.conf minix-sys +./usr/tests/minix-posix/blocktest/test.sh minix-sys ./usr/tests/minix-posix/run minix-sys ./usr/tests/minix-posix/t10a minix-sys ./usr/tests/minix-posix/t11a minix-sys @@ -5674,12 +5680,6 @@ ./usr/tests/minix-posix/testvm.conf minix-sys ./usr/tests/minix-posix/testvnd minix-sys ./usr/tests/minix-posix/tvnd minix-sys -./usr/tests/minix-posix/blocktest minix-sys -./usr/tests/minix-posix/blocktest/README minix-sys -./usr/tests/minix-posix/blocktest/blocktest minix-sys -./usr/tests/minix-posix/blocktest/support.sh minix-sys -./usr/tests/minix-posix/blocktest/system.conf minix-sys -./usr/tests/minix-posix/blocktest/test.sh minix-sys ./usr/tests/usr.bin/jot/Atffile minix-sys atf ./usr/tests/usr.bin/jot/d_basic.out minix-sys atf ./usr/tests/usr.bin/jot/t_jot minix-sys atf diff --git a/external/bsd/mdocml/Makefile.inc b/external/bsd/mdocml/Makefile.inc index 242aa02a1..a21175ba5 100644 --- a/external/bsd/mdocml/Makefile.inc +++ b/external/bsd/mdocml/Makefile.inc @@ -1,4 +1,4 @@ -# $NetBSD: Makefile.inc,v 1.12 2010/07/25 19:16:18 joerg Exp $ +# $NetBSD: Makefile.inc,v 1.15 2012/02/16 22:56:12 joerg Exp $ .include @@ -8,14 +8,15 @@ CPPFLAGS+= -DVERSION=\"${VERSION}\" -DUGLY CPPFLAGS+= -UOSNAME -DOSNAME=\"Minix\" .if (${HOSTPROG:U} == "") -CPPFLAGS+= -DHAVE_STRLCAT -DHAVE_STRLCPY -DHAVE_STRPTIME -DHAVE_MMAP +# Minix mmap not yet up to the task +CPPFLAGS+= -DHAVE_STRLCAT -DHAVE_STRLCPY -DHAVE_STRPTIME #-DHAVE_MMAP .endif DISTDIR:= ${.PARSEDIR}/dist .PATH: ${DISTDIR} -.for _LIB in man mdoc roff +.for _LIB in mandoc MDOCMLOBJDIR.${_LIB} != cd ${.PARSEDIR}/lib/lib${_LIB} && ${PRINTOBJDIR} MDOCMLLIB.${_LIB}= ${MDOCMLOBJDIR.${_LIB}}/lib${_LIB}.a .endfor diff --git a/external/bsd/mdocml/bin/mandoc/Makefile b/external/bsd/mdocml/bin/mandoc/Makefile index 741409b63..b86185395 100644 --- a/external/bsd/mdocml/bin/mandoc/Makefile +++ b/external/bsd/mdocml/bin/mandoc/Makefile @@ -1,24 +1,22 @@ -# $NetBSD: Makefile,v 1.4 2011/01/12 23:02:21 joerg Exp $ +# $NetBSD: Makefile,v 1.6 2011/10/11 19:20:13 joerg Exp $ .include PROG= mandoc -SRCS= main.c mdoc_term.c chars.c term.c term_ascii.c term_ps.c \ - tbl_term.c tbl_html.c tree.c compat.c \ - man_term.c html.c mdoc_html.c man_html.c out.c +SRCS= chars.c main.c out.c tree.c \ + eqn_html.c eqn_term.c \ + html.c man_html.c mdoc_html.c tbl_html.c \ + man_term.c mdoc_term.c term.c term_ascii.c \ + term_ps.c tbl_term.c .ifndef HOSTPROG -DPADD+= ${MDOCMLLIB.man} ${MDOCMLLIB.mdoc} ${MDOCMLLIB.roff} -LDADD+= -L${MDOCMLOBJDIR.man} -lman \ - -L${MDOCMLOBJDIR.mdoc} -lmdoc \ - -L${MDOCMLOBJDIR.roff} -lroff +DPADD+= ${MDOCMLLIB.mandoc} +LDADD+= -L${MDOCMLOBJDIR.mandoc} -lmandoc .else -SRCS.libman!= cd ${.PARSEDIR}/../../lib/libman && ${MAKE} -V '$${SRCS}' -SRCS.libmdoc!= cd ${.PARSEDIR}/../../lib/libmdoc && ${MAKE} -V '$${SRCS}' -SRCS.libroff!= cd ${.PARSEDIR}/../../lib/libroff && ${MAKE} -V '$${SRCS}' +SRCS.libmandoc!=cd ${.PARSEDIR}/../../lib/libmandoc && ${MAKE} -V '$${SRCS}' -SRCS+= ${SRCS.libman} ${SRCS.libmdoc:Nmandoc.c} ${SRCS.libroff} +SRCS+= ${SRCS.libmandoc} .endif .include diff --git a/external/bsd/mdocml/dist/Makefile b/external/bsd/mdocml/dist/Makefile index 87d9e5ca1..bf4b0edce 100644 --- a/external/bsd/mdocml/dist/Makefile +++ b/external/bsd/mdocml/dist/Makefile @@ -1,346 +1,643 @@ -.SUFFIXES: .html .xml .sgml .1 .3 .7 .md5 .tar.gz -.SUFFIXES: .1.txt .3.txt .7.txt -.SUFFIXES: .1.xhtml .3.xhtml .7.xhtml -.SUFFIXES: .1.sgml .3.sgml .7.sgml -.SUFFIXES: .h .h.html -.SUFFIXES: .1.ps .3.ps .7.ps -.SUFFIXES: .1.pdf .3.pdf .7.pdf - -PREFIX = /usr/local -BINDIR = $(PREFIX)/bin -INCLUDEDIR = $(PREFIX)/include -LIBDIR = $(PREFIX)/lib -MANDIR = $(PREFIX)/man -EXAMPLEDIR = $(PREFIX)/share/examples/mandoc -INSTALL = install -INSTALL_PROGRAM = $(INSTALL) -m 0755 -INSTALL_DATA = $(INSTALL) -m 0444 -INSTALL_LIB = $(INSTALL) -m 0644 -INSTALL_MAN = $(INSTALL_DATA) - -VERSION = 1.10.9 -VDATE = 07 January 2010 - -VFLAGS = -DVERSION="\"$(VERSION)\"" -WFLAGS = -W -Wall -Wstrict-prototypes -Wno-unused-parameter -Wwrite-strings -CFLAGS += -g $(WFLAGS) $(VFLAGS) -DHAVE_CONFIG_H +.PHONY: clean install installwww +.SUFFIXES: .sgml .html .md5 .h .h.html +.SUFFIXES: .1 .3 .7 .8 +.SUFFIXES: .1.txt .3.txt .7.txt .8.txt +.SUFFIXES: .1.pdf .3.pdf .7.pdf .8.pdf +.SUFFIXES: .1.ps .3.ps .7.ps .8.ps +.SUFFIXES: .1.html .3.html .7.html .8.html +.SUFFIXES: .1.xhtml .3.xhtml .7.xhtml .8.xhtml # Specify this if you want to hard-code the operating system to appear # in the lower-left hand corner of -mdoc manuals. -# CFLAGS += -DOSNAME="\"OpenBSD 4.5\"" -CFLAGS += -UOSNAME -DOSNAME="\"Minix\"" +# +# CFLAGS += -DOSNAME="\"OpenBSD 4.5\"" -LINTFLAGS += $(VFLAGS) +VERSION = 1.12.0 +VDATE = 8 October 2011 -ROFFLNS = roff.ln tbl.ln tbl_opts.ln tbl_layout.ln tbl_data.ln +# IFF your system supports multi-byte functions (setlocale(), wcwidth(), +# putwchar()) AND has __STDC_ISO_10646__ (that is, wchar_t is simply a +# UCS-4 value) should you define USE_WCHAR. If you define it and your +# system DOESN'T support this, -Tlocale will produce garbage. +# If you don't define it, -Tlocale is a synonym for -Tacsii. +# +CFLAGS += -DUSE_WCHAR -ROFFSRCS = roff.c tbl.c tbl_opts.c tbl_layout.c tbl_data.c +# If your system has manpath(1), uncomment this. This is most any +# system that's not OpenBSD or NetBSD. If uncommented, apropos(1), +# mandocdb(8), and man.cgi will popen(3) manpath(1) to get the MANPATH +# variable. +#CFLAGS += -DUSE_MANPATH -ROFFOBJS = roff.o tbl.o tbl_opts.o tbl_layout.o tbl_data.o +# If your system supports static binaries only, uncomment this. This +# appears only to be BSD UNIX systems (Mac OS X has no support and Linux +# requires -pthreads for static libdb). +STATIC = -static -MANDOCLNS = mandoc.ln +CFLAGS += -g -DHAVE_CONFIG_H -DVERSION="\"$(VERSION)\"" +CFLAGS += -W -Wall -Wstrict-prototypes -Wno-unused-parameter -Wwrite-strings +PREFIX = /usr/local +WWWPREFIX = /var/www +HTDOCDIR = $(WWWPREFIX)/htdocs +CGIBINDIR = $(WWWPREFIX)/cgi-bin +BINDIR = $(PREFIX)/bin +INCLUDEDIR = $(PREFIX)/include/mandoc +LIBDIR = $(PREFIX)/lib/mandoc +MANDIR = $(PREFIX)/man +EXAMPLEDIR = $(PREFIX)/share/examples/mandoc +INSTALL = install +INSTALL_PROGRAM = $(INSTALL) -m 0755 +INSTALL_DATA = $(INSTALL) -m 0444 +INSTALL_LIB = $(INSTALL) -m 0644 +INSTALL_SOURCE = $(INSTALL) -m 0644 +INSTALL_MAN = $(INSTALL_DATA) -MANDOCSRCS = mandoc.c +# Non-BSD systems (Linux, etc.) need -ldb to compile mandocdb and +# apropos. +# However, if you don't have -ldb at all (or it's not native), then +# comment out apropos and mandocdb. +# +#DBLIB = -ldb +DBBIN = apropos mandocdb man.cgi catman whatis +DBLN = llib-lapropos.ln llib-lmandocdb.ln llib-lman.cgi.ln llib-lcatman.ln -MANDOCOBJS = mandoc.o +all: mandoc preconv demandoc $(DBBIN) -MDOCLNS = mdoc_macro.ln mdoc.ln mdoc_hash.ln mdoc_strings.ln \ - mdoc_argv.ln mdoc_validate.ln \ - lib.ln att.ln arch.ln vol.ln msec.ln st.ln +SRCS = Makefile \ + TODO \ + apropos.1 \ + apropos.c \ + apropos_db.c \ + apropos_db.h \ + arch.c \ + arch.in \ + att.c \ + att.in \ + catman.8 \ + catman.c \ + cgi.c \ + chars.c \ + chars.in \ + compat_fgetln.c \ + compat_getsubopt.c \ + compat_strlcat.c \ + compat_strlcpy.c \ + config.h.post \ + config.h.pre \ + demandoc.1 \ + demandoc.c \ + eqn.7 \ + eqn.c \ + eqn_html.c \ + eqn_term.c \ + example.style.css \ + external.png \ + html.c \ + html.h \ + index.css \ + index.sgml \ + lib.c \ + lib.in \ + libman.h \ + libmandoc.h \ + libmdoc.h \ + libroff.h \ + main.c \ + main.h \ + man.7 \ + man.c \ + man.cgi.7 \ + man-cgi.css \ + man.h \ + man_hash.c \ + man_html.c \ + man_macro.c \ + man_term.c \ + man_validate.c \ + mandoc.1 \ + mandoc.3 \ + mandoc.c \ + mandoc.h \ + mandoc_char.7 \ + mandocdb.8 \ + mandocdb.c \ + mandocdb.h \ + manpath.c \ + manpath.h \ + mdoc.7 \ + mdoc.c \ + mdoc.h \ + mdoc_argv.c \ + mdoc_hash.c \ + mdoc_html.c \ + mdoc_macro.c \ + mdoc_man.c \ + mdoc_term.c \ + mdoc_validate.c \ + msec.c \ + msec.in \ + out.c \ + out.h \ + preconv.1 \ + preconv.c \ + predefs.in \ + read.c \ + regress \ + roff.7 \ + roff.c \ + st.c \ + st.in \ + style.css \ + tbl.7 \ + tbl.c \ + tbl_data.c \ + tbl_html.c \ + tbl_layout.c \ + tbl_opts.c \ + tbl_term.c \ + term.c \ + term.h \ + term_ascii.c \ + term_ps.c \ + test-fgetln.c \ + test-getsubopt.c \ + test-mmap.c \ + test-strlcat.c \ + test-strlcpy.c \ + test-strptime.c \ + tree.c \ + vol.c \ + vol.in \ + whatis.1 -MDOCOBJS = mdoc_macro.o mdoc.o mdoc_hash.o mdoc_strings.o \ - mdoc_argv.o mdoc_validate.o lib.o att.o \ - arch.o vol.o msec.o st.o +LIBMAN_OBJS = man.o \ + man_hash.o \ + man_macro.o \ + man_validate.o +LIBMAN_LNS = man.ln \ + man_hash.ln \ + man_macro.ln \ + man_validate.ln -MDOCSRCS = mdoc_macro.c mdoc.c mdoc_hash.c mdoc_strings.c \ - mdoc_argv.c mdoc_validate.c lib.c att.c \ - arch.c vol.c msec.c st.c +LIBMDOC_OBJS = arch.o \ + att.o \ + lib.o \ + mdoc.o \ + mdoc_argv.o \ + mdoc_hash.o \ + mdoc_macro.o \ + mdoc_validate.o \ + st.o \ + vol.o +LIBMDOC_LNS = arch.ln \ + att.ln \ + lib.ln \ + mdoc.ln \ + mdoc_argv.ln \ + mdoc_hash.ln \ + mdoc_macro.ln \ + mdoc_validate.ln \ + st.ln \ + vol.ln -MANLNS = man_macro.ln man.ln man_hash.ln man_validate.ln \ - man_argv.ln +LIBROFF_OBJS = eqn.o \ + roff.o \ + tbl.o \ + tbl_data.o \ + tbl_layout.o \ + tbl_opts.o +LIBROFF_LNS = eqn.ln \ + roff.ln \ + tbl.ln \ + tbl_data.ln \ + tbl_layout.ln \ + tbl_opts.ln -MANOBJS = man_macro.o man.o man_hash.o man_validate.o \ - man_argv.o -MANSRCS = man_macro.c man.c man_hash.c man_validate.c \ - man_argv.c +LIBMANDOC_OBJS = $(LIBMAN_OBJS) \ + $(LIBMDOC_OBJS) \ + $(LIBROFF_OBJS) \ + chars.o \ + mandoc.o \ + msec.o \ + read.o +LIBMANDOC_LNS = $(LIBMAN_LNS) \ + $(LIBMDOC_LNS) \ + $(LIBROFF_LNS) \ + chars.ln \ + mandoc.ln \ + msec.ln \ + read.ln -MAINLNS = main.ln mdoc_term.ln chars.ln term.ln tree.ln \ - compat.ln man_term.ln html.ln mdoc_html.ln \ - man_html.ln out.ln term_ps.ln term_ascii.ln \ - tbl_term.ln tbl_html.ln +COMPAT_OBJS = compat_fgetln.o \ + compat_getsubopt.o \ + compat_strlcat.o \ + compat_strlcpy.o +COMPAT_LNS = compat_fgetln.ln \ + compat_getsubopt.ln \ + compat_strlcat.ln \ + compat_strlcpy.ln -MAINOBJS = main.o mdoc_term.o chars.o term.o tree.o compat.o \ - man_term.o html.o mdoc_html.o man_html.o out.o \ - term_ps.o term_ascii.o tbl_term.o tbl_html.o +arch.o arch.ln: arch.in +att.o att.ln: att.in +chars.o chars.ln: chars.in +lib.o lib.ln: lib.in +msec.o msec.ln: msec.in +roff.o roff.ln: predefs.in +st.o st.ln: st.in +vol.o vol.ln: vol.in -MAINSRCS = main.c mdoc_term.c chars.c term.c tree.c compat.c \ - man_term.c html.c mdoc_html.c man_html.c out.c \ - term_ps.c term_ascii.c tbl_term.c tbl_html.c +$(LIBMAN_OBJS) $(LIBMAN_LNS): libman.h +$(LIBMDOC_OBJS) $(LIBMDOC_LNS): libmdoc.h +$(LIBROFF_OBJS) $(LIBROFF_LNS): libroff.h +$(LIBMANDOC_OBJS) $(LIBMANDOC_LNS): mandoc.h mdoc.h man.h libmandoc.h config.h -LLNS = llib-llibmdoc.ln llib-llibman.ln llib-lmandoc.ln \ - llib-llibmandoc.ln llib-llibroff.ln +$(COMPAT_OBJS) $(COMPAT_LNS): config.h -LNS = $(MAINLNS) $(MDOCLNS) $(MANLNS) \ - $(MANDOCLNS) $(ROFFLNS) +MANDOC_HTML_OBJS = eqn_html.o \ + html.o \ + man_html.o \ + mdoc_html.o \ + tbl_html.o +MANDOC_HTML_LNS = eqn_html.ln \ + html.ln \ + man_html.ln \ + mdoc_html.ln \ + tbl_html.ln -LIBS = libmdoc.a libman.a libmandoc.a libroff.a +MANDOC_MAN_OBJS = mdoc_man.o +MANDOC_MAN_LNS = mdoc_man.ln -OBJS = $(MDOCOBJS) $(MAINOBJS) $(MANOBJS) \ - $(MANDOCOBJS) $(ROFFOBJS) +MANDOC_TERM_OBJS = eqn_term.o \ + man_term.o \ + mdoc_term.o \ + term.o \ + term_ascii.o \ + term_ps.o \ + tbl_term.o +MANDOC_TERM_LNS = eqn_term.ln \ + man_term.ln \ + mdoc_term.ln \ + term.ln \ + term_ascii.ln \ + term_ps.ln \ + tbl_term.ln -SRCS = $(MDOCSRCS) $(MAINSRCS) $(MANSRCS) \ - $(MANDOCSRCS) $(ROFFSRCS) +MANDOC_OBJS = $(MANDOC_HTML_OBJS) \ + $(MANDOC_MAN_OBJS) \ + $(MANDOC_TERM_OBJS) \ + main.o \ + out.o \ + tree.o +MANDOC_LNS = $(MANDOC_HTML_LNS) \ + $(MANDOC_MAN_LNS) \ + $(MANDOC_TERM_LNS) \ + main.ln \ + out.ln \ + tree.ln -DATAS = arch.in att.in lib.in msec.in st.in \ - vol.in chars.in +$(MANDOC_HTML_OBJS) $(MANDOC_HTML_LNS): html.h +$(MANDOC_TERM_OBJS) $(MANDOC_TERM_LNS): term.h +$(MANDOC_OBJS) $(MANDOC_LNS): main.h mandoc.h mdoc.h man.h config.h out.h -HEADS = mdoc.h libmdoc.h man.h libman.h term.h \ - libmandoc.h html.h chars.h out.h main.h roff.h \ - mandoc.h libroff.h +MANDOCDB_OBJS = mandocdb.o manpath.o +MANDOCDB_LNS = mandocdb.ln manpath.ln -GSGMLS = mandoc.1.sgml mdoc.3.sgml mdoc.7.sgml \ - mandoc_char.7.sgml man.7.sgml man.3.sgml roff.7.sgml \ - roff.3.sgml tbl.7.sgml +$(MANDOCDB_OBJS) $(MANDOCDB_LNS): mandocdb.h mandoc.h mdoc.h man.h config.h manpath.h -SGMLS = index.sgml +PRECONV_OBJS = preconv.o +PRECONV_LNS = preconv.ln -XHTMLS = mandoc.1.xhtml mdoc.3.xhtml \ - man.3.xhtml mdoc.7.xhtml man.7.xhtml mandoc_char.7.xhtml \ - roff.7.xhtml roff.3.xhtml tbl.7.xhtml +$(PRECONV_OBJS) $(PRECONV_LNS): config.h -HTMLS = ChangeLog.html index.html man.h.html mdoc.h.html \ - mandoc.h.html roff.h.html mandoc.1.html mdoc.3.html \ - man.3.html mdoc.7.html man.7.html mandoc_char.7.html \ - roff.7.html roff.3.html tbl.7.html +APROPOS_OBJS = apropos.o apropos_db.o manpath.o +APROPOS_LNS = apropos.ln apropos_db.ln manpath.ln -PSS = mandoc.1.ps mdoc.3.ps man.3.ps mdoc.7.ps man.7.ps \ - mandoc_char.7.ps roff.7.ps roff.3.ps tbl.7.ps +$(APROPOS_OBJS) $(APROPOS_LNS): config.h mandoc.h apropos_db.h manpath.h mandocdb.h -PDFS = mandoc.1.pdf mdoc.3.pdf man.3.pdf mdoc.7.pdf man.7.pdf \ - mandoc_char.7.pdf roff.7.pdf roff.3.pdf tbl.7.pdf +CGI_OBJS = $(MANDOC_HTML_OBJS) \ + $(MANDOC_MAN_OBJS) \ + $(MANDOC_TERM_OBJS) \ + cgi.o \ + apropos_db.o \ + manpath.o \ + out.o \ + tree.o -XSLS = ChangeLog.xsl +CGI_LNS = $(MANDOC_HTML_LNS) \ + $(MANDOC_MAN_LNS) \ + $(MANDOC_TERM_LNS) \ + cgi.ln \ + apropos_db.ln \ + manpath.ln \ + out.ln \ + tree.ln -TEXTS = mandoc.1.txt mdoc.3.txt man.3.txt mdoc.7.txt man.7.txt \ - mandoc_char.7.txt ChangeLog.txt \ - roff.7.txt roff.3.txt tbl.7.txt +$(CGI_OBJS) $(CGI_LNS): main.h mdoc.h man.h out.h config.h mandoc.h apropos_db.h manpath.h mandocdb.h -EXAMPLES = example.style.css +CATMAN_OBJS = catman.o manpath.o +CATMAN_LNS = catman.ln manpath.ln -XMLS = ChangeLog.xml +$(CATMAN_OBJS) $(CATMAN_LNS): config.h mandoc.h manpath.h mandocdb.h -STATICS = index.css style.css external.png +DEMANDOC_OBJS = demandoc.o +DEMANDOC_LNS = demandoc.ln -MD5S = mdocml-$(VERSION).md5 +$(DEMANDOC_OBJS) $(DEMANDOC_LNS): config.h -TARGZS = mdocml-$(VERSION).tar.gz +INDEX_MANS = apropos.1.html \ + apropos.1.xhtml \ + apropos.1.ps \ + apropos.1.pdf \ + apropos.1.txt \ + catman.8.html \ + catman.8.xhtml \ + catman.8.ps \ + catman.8.pdf \ + catman.8.txt \ + demandoc.1.html \ + demandoc.1.xhtml \ + demandoc.1.ps \ + demandoc.1.pdf \ + demandoc.1.txt \ + mandoc.1.html \ + mandoc.1.xhtml \ + mandoc.1.ps \ + mandoc.1.pdf \ + mandoc.1.txt \ + whatis.1.html \ + whatis.1.xhtml \ + whatis.1.ps \ + whatis.1.pdf \ + whatis.1.txt \ + mandoc.3.html \ + mandoc.3.xhtml \ + mandoc.3.ps \ + mandoc.3.pdf \ + mandoc.3.txt \ + eqn.7.html \ + eqn.7.xhtml \ + eqn.7.ps \ + eqn.7.pdf \ + eqn.7.txt \ + man.7.html \ + man.7.xhtml \ + man.7.ps \ + man.7.pdf \ + man.7.txt \ + man.cgi.7.html \ + man.cgi.7.xhtml \ + man.cgi.7.ps \ + man.cgi.7.pdf \ + man.cgi.7.txt \ + mandoc_char.7.html \ + mandoc_char.7.xhtml \ + mandoc_char.7.ps \ + mandoc_char.7.pdf \ + mandoc_char.7.txt \ + mdoc.7.html \ + mdoc.7.xhtml \ + mdoc.7.ps \ + mdoc.7.pdf \ + mdoc.7.txt \ + preconv.1.html \ + preconv.1.xhtml \ + preconv.1.ps \ + preconv.1.pdf \ + preconv.1.txt \ + roff.7.html \ + roff.7.xhtml \ + roff.7.ps \ + roff.7.pdf \ + roff.7.txt \ + tbl.7.html \ + tbl.7.xhtml \ + tbl.7.ps \ + tbl.7.pdf \ + tbl.7.txt \ + mandocdb.8.html \ + mandocdb.8.xhtml \ + mandocdb.8.ps \ + mandocdb.8.pdf \ + mandocdb.8.txt -MANS = mandoc.1 mdoc.3 mdoc.7 mandoc_char.7 man.7 \ - man.3 roff.7 roff.3 tbl.7 +$(INDEX_MANS): mandoc -BINS = mandoc +INDEX_OBJS = $(INDEX_MANS) \ + man.h.html \ + mandoc.h.html \ + mdoc.h.html \ + mdocml.tar.gz \ + mdocml.md5 -TESTS = test-strlcat.c test-strlcpy.c +www: index.html -CONFIGS = config.h.pre config.h.post - -DOCLEAN = $(BINS) $(LNS) $(LLNS) $(LIBS) $(OBJS) $(HTMLS) \ - $(TARGZS) tags $(MD5S) $(XMLS) $(TEXTS) $(GSGMLS) \ - config.h config.log $(PSS) $(PDFS) $(XHTMLS) - -DOINSTALL = $(SRCS) $(HEADS) Makefile $(MANS) $(SGMLS) $(STATICS) \ - $(DATAS) $(XSLS) $(EXAMPLES) $(TESTS) $(CONFIGS) - -all: $(BINS) - -lint: $(LLNS) +lint: llib-lmandoc.ln llib-lpreconv.ln llib-ldemandoc.ln $(DBLN) clean: - rm -f $(DOCLEAN) + rm -f libmandoc.a $(LIBMANDOC_OBJS) + rm -f llib-llibmandoc.ln $(LIBMANDOC_LNS) + rm -f mandocdb $(MANDOCDB_OBJS) + rm -f llib-lmandocdb.ln $(MANDOCDB_LNS) + rm -f preconv $(PRECONV_OBJS) + rm -f llib-lpreconv.ln $(PRECONV_LNS) + rm -f apropos whatis $(APROPOS_OBJS) + rm -f llib-lapropos.ln $(APROPOS_LNS) + rm -f man.cgi $(CGI_OBJS) + rm -f llib-lman.cgi.ln $(CGI_LNS) + rm -f catman $(CATMAN_OBJS) + rm -f llib-lcatman.ln $(CATMAN_LNS) + rm -f demandoc $(DEMANDOC_OBJS) + rm -f llib-ldemandoc.ln $(DEMANDOC_LNS) + rm -f mandoc $(MANDOC_OBJS) + rm -f llib-lmandoc.ln $(MANDOC_LNS) + rm -f config.h config.log $(COMPAT_OBJS) $(COMPAT_LNS) + rm -f mdocml.tar.gz mdocml-win32.zip mdocml-win64.zip mdocml-macosx.zip + rm -f index.html $(INDEX_OBJS) + rm -rf test-fgetln.DSYM + rm -rf test-strlcpy.DSYM + rm -rf test-strlcat.DSYM + rm -rf test-strptime.DSYM + rm -rf test-mmap.DSYM + rm -rf test-getsubopt.DSYM -dist: mdocml-$(VERSION).tar.gz - -www: all $(GSGMLS) $(HTMLS) $(XHTMLS) $(TEXTS) $(MD5S) $(TARGZS) $(PSS) $(PDFS) - -ps: $(PSS) - -pdf: $(PDFS) - -installwww: www - $(INSTALL_DATA) $(HTMLS) $(XHTMLS) $(PSS) $(PDFS) $(TEXTS) $(STATICS) $(DESTDIR)$(PREFIX)/ - $(INSTALL_DATA) mdocml-$(VERSION).tar.gz $(DESTDIR)$(PREFIX)/snapshots/ - $(INSTALL_DATA) mdocml-$(VERSION).md5 $(DESTDIR)$(PREFIX)/snapshots/ - $(INSTALL_DATA) mdocml-$(VERSION).tar.gz $(DESTDIR)$(PREFIX)/snapshots/mdocml.tar.gz - $(INSTALL_DATA) mdocml-$(VERSION).md5 $(DESTDIR)$(PREFIX)/snapshots/mdocml.md5 - -install: +install: all mkdir -p $(DESTDIR)$(BINDIR) mkdir -p $(DESTDIR)$(EXAMPLEDIR) + mkdir -p $(DESTDIR)$(LIBDIR) + mkdir -p $(DESTDIR)$(INCLUDEDIR) mkdir -p $(DESTDIR)$(MANDIR)/man1 + mkdir -p $(DESTDIR)$(MANDIR)/man3 mkdir -p $(DESTDIR)$(MANDIR)/man7 - $(INSTALL_PROGRAM) mandoc $(DESTDIR)$(BINDIR) - $(INSTALL_MAN) mandoc.1 $(DESTDIR)$(MANDIR)/man1 - $(INSTALL_MAN) man.7 mdoc.7 roff.7 tbl.7 mandoc_char.7 $(DESTDIR)$(MANDIR)/man7 + mkdir -p $(DESTDIR)$(MANDIR)/man8 + $(INSTALL_PROGRAM) mandoc preconv demandoc $(DESTDIR)$(BINDIR) + $(INSTALL_LIB) libmandoc.a $(DESTDIR)$(LIBDIR) + $(INSTALL_LIB) man.h mdoc.h mandoc.h $(DESTDIR)$(INCLUDEDIR) + $(INSTALL_MAN) mandoc.1 preconv.1 demandoc.1 $(DESTDIR)$(MANDIR)/man1 + $(INSTALL_MAN) mandoc.3 $(DESTDIR)$(MANDIR)/man3 + $(INSTALL_MAN) man.7 mdoc.7 roff.7 eqn.7 tbl.7 mandoc_char.7 $(DESTDIR)$(MANDIR)/man7 $(INSTALL_DATA) example.style.css $(DESTDIR)$(EXAMPLEDIR) -uninstall: - rm -f $(DESTDIR)$(BINDIR)/mandoc - rm -f $(DESTDIR)$(MANDIR)/man1/mandoc.1 - rm -f $(DESTDIR)$(MANDIR)/man7/mdoc.7 - rm -f $(DESTDIR)$(MANDIR)/man7/roff.7 - rm -f $(DESTDIR)$(MANDIR)/man7/tbl.7 - rm -f $(DESTDIR)$(MANDIR)/man7/man.7 - rm -f $(DESTDIR)$(MANDIR)/man7/mandoc_char.7 - rm -f $(DESTDIR)$(EXAMPLEDIR)/example.style.css +installcgi: all + mkdir -p $(DESTDIR)$(CGIBINDIR) + mkdir -p $(DESTDIR)$(HTDOCDIR) + $(INSTALL_PROGRAM) man.cgi $(DESTDIR)$(CGIBINDIR) + $(INSTALL_DATA) example.style.css $(DESTDIR)$(HTDOCDIR)/man.css + $(INSTALL_DATA) man-cgi.css $(DESTDIR)$(HTDOCDIR) -$(OBJS): config.h +installwww: www + mkdir -p $(PREFIX)/snapshots + mkdir -p $(PREFIX)/binaries + $(INSTALL_DATA) index.html external.png index.css $(PREFIX) + $(INSTALL_DATA) $(INDEX_MANS) style.css $(PREFIX) + $(INSTALL_DATA) mandoc.h.html man.h.html mdoc.h.html $(PREFIX) + $(INSTALL_DATA) mdocml.tar.gz $(PREFIX)/snapshots + $(INSTALL_DATA) mdocml.md5 $(PREFIX)/snapshots + $(INSTALL_DATA) mdocml.tar.gz $(PREFIX)/snapshots/mdocml-$(VERSION).tar.gz + $(INSTALL_DATA) mdocml.md5 $(PREFIX)/snapshots/mdocml-$(VERSION).md5 -$(LNS): config.h +libmandoc.a: $(COMPAT_OBJS) $(LIBMANDOC_OBJS) + $(AR) rs $@ $(COMPAT_OBJS) $(LIBMANDOC_OBJS) -man_macro.ln man_macro.o: man_macro.c libman.h +llib-llibmandoc.ln: $(COMPAT_LNS) $(LIBMANDOC_LNS) + $(LINT) $(LINTFLAGS) -Clibmandoc $(COMPAT_LNS) $(LIBMANDOC_LNS) -lib.ln lib.o: lib.c lib.in libmdoc.h +mandoc: $(MANDOC_OBJS) libmandoc.a + $(CC) $(LDFLAGS) -o $@ $(MANDOC_OBJS) libmandoc.a -att.ln att.o: att.c att.in libmdoc.h +llib-lmandoc.ln: $(MANDOC_LNS) llib-llibmandoc.ln + $(LINT) $(LINTFLAGS) -Cmandoc $(MANDOC_LNS) llib-llibmandoc.ln -arch.ln arch.o: arch.c arch.in libmdoc.h +mandocdb: $(MANDOCDB_OBJS) libmandoc.a + $(CC) $(LDFLAGS) -o $@ $(MANDOCDB_OBJS) libmandoc.a $(DBLIB) -vol.ln vol.o: vol.c vol.in libmdoc.h +llib-lmandocdb.ln: $(MANDOCDB_LNS) llib-llibmandoc.ln + $(LINT) $(LINTFLAGS) -Cmandocdb $(MANDOCDB_LNS) llib-llibmandoc.ln -chars.ln chars.o: chars.c chars.in chars.h +preconv: $(PRECONV_OBJS) + $(CC) $(LDFLAGS) -o $@ $(PRECONV_OBJS) -msec.ln msec.o: msec.c msec.in libmdoc.h +llib-lpreconv.ln: $(PRECONV_LNS) llib-llibmandoc.ln + $(LINT) $(LINTFLAGS) -Cpreconv $(PRECONV_LNS) llib-llibmandoc.ln -st.ln st.o: st.c st.in libmdoc.h +whatis: apropos + cp -f apropos whatis -mdoc_macro.ln mdoc_macro.o: mdoc_macro.c libmdoc.h +apropos: $(APROPOS_OBJS) libmandoc.a + $(CC) $(LDFLAGS) -o $@ $(APROPOS_OBJS) libmandoc.a $(DBLIB) -mdoc_term.ln mdoc_term.o: mdoc_term.c term.h mdoc.h +llib-lapropos.ln: $(APROPOS_LNS) llib-llibmandoc.ln + $(LINT) $(LINTFLAGS) -Capropos $(APROPOS_LNS) llib-llibmandoc.ln -mdoc_strings.ln mdoc_strings.o: mdoc_strings.c libmdoc.h +catman: $(CATMAN_OBJS) libmandoc.a + $(CC) $(LDFLAGS) -o $@ $(CATMAN_OBJS) libmandoc.a $(DBLIB) -man_hash.ln man_hash.o: man_hash.c libman.h +llib-lcatman.ln: $(CATMAN_LNS) llib-llibmandoc.ln + $(LINT) $(LINTFLAGS) -Ccatman $(CATMAN_LNS) llib-llibmandoc.ln -mdoc_hash.ln mdoc_hash.o: mdoc_hash.c libmdoc.h +man.cgi: $(CGI_OBJS) libmandoc.a + $(CC) $(LDFLAGS) $(STATIC) -o $@ $(CGI_OBJS) libmandoc.a $(DBLIB) -mdoc.ln mdoc.o: mdoc.c libmdoc.h +llib-lman.cgi.ln: $(CGI_LNS) llib-llibmandoc.ln + $(LINT) $(LINTFLAGS) -Cman.cgi $(CGI_LNS) llib-llibmandoc.ln -man.ln man.o: man.c libman.h +demandoc: $(DEMANDOC_OBJS) libmandoc.a + $(CC) $(LDFLAGS) -o $@ $(DEMANDOC_OBJS) libmandoc.a -main.ln main.o: main.c mdoc.h man.h roff.h +llib-ldemandoc.ln: $(DEMANDOC_LNS) llib-llibmandoc.ln + $(LINT) $(LINTFLAGS) -Cdemandoc $(DEMANDOC_LNS) llib-llibmandoc.ln -compat.ln compat.o: compat.c +mdocml.md5: mdocml.tar.gz + md5 mdocml.tar.gz >$@ -term.ln term.o: term.c term.h man.h mdoc.h chars.h - -term_ps.ln term_ps.o: term_ps.c term.h main.h - -term_ascii.ln term_ascii.o: term_ascii.c term.h main.h - -html.ln html.o: html.c html.h chars.h - -mdoc_html.ln mdoc_html.o: mdoc_html.c html.h mdoc.h - -man_html.ln man_html.o: man_html.c html.h man.h out.h - -out.ln out.o: out.c out.h - -mandoc.ln mandoc.o: mandoc.c libmandoc.h - -tree.ln tree.o: tree.c man.h mdoc.h - -mdoc_argv.ln mdoc_argv.o: mdoc_argv.c libmdoc.h - -man_argv.ln man_argv.o: man_argv.c libman.h - -man_validate.ln man_validate.o: man_validate.c libman.h - -mdoc_validate.ln mdoc_validate.o: mdoc_validate.c libmdoc.h - -libmdoc.h: mdoc.h - -ChangeLog.xml: - cvs2cl --xml --xml-encoding iso-8859-15 -t --noxmlns -f $@ - -ChangeLog.txt: - cvs2cl -t -f $@ - -ChangeLog.html: ChangeLog.xml ChangeLog.xsl - xsltproc -o $@ ChangeLog.xsl ChangeLog.xml - -mdocml-$(VERSION).tar.gz: $(DOINSTALL) - mkdir -p .dist/mdocml/mdocml-$(VERSION)/ - cp -f $(DOINSTALL) .dist/mdocml/mdocml-$(VERSION)/ - ( cd .dist/mdocml/ && tar zcf ../../$@ mdocml-$(VERSION)/ ) +mdocml.tar.gz: $(SRCS) + mkdir -p .dist/mdocml-$(VERSION)/ + $(INSTALL_SOURCE) $(SRCS) .dist/mdocml-$(VERSION) + ( cd .dist/ && tar zcf ../$@ ./ ) rm -rf .dist/ -llib-llibmdoc.ln: $(MDOCLNS) - $(LINT) -Clibmdoc $(MDOCLNS) +mdocml-win32.zip: $(SRCS) + mkdir -p .win32/mdocml-$(VERSION)/ + $(INSTALL_SOURCE) $(SRCS) .win32 + cp .win32/Makefile .win32/Makefile.old + egrep -v -e DUSE_WCHAR -e ^DBBIN .win32/Makefile.old >.win32/Makefile + ( cd .win32; \ + CC=i686-w64-mingw32-gcc AR=i686-w64-mingw32-ar CFLAGS='-DOSNAME=\"Windows\"' make; \ + make install PREFIX=mdocml-$(VERSION) ; \ + zip -r ../$@ mdocml-$(VERSION) ) + rm -rf .win32 -llib-llibman.ln: $(MANLNS) - $(LINT) -Clibman $(MANLNS) +mdocml-win64.zip: $(SRCS) + mkdir -p .win64/mdocml-$(VERSION)/ + $(INSTALL_SOURCE) $(SRCS) .win64 + cp .win64/Makefile .win64/Makefile.old + egrep -v -e DUSE_WCHAR -e ^DBBIN .win64/Makefile.old >.win64/Makefile + ( cd .win64; \ + CC=x86_64-w64-mingw32-gcc AR=x86_64-w64-mingw32-ar CFLAGS='-DOSNAME=\"Windows\"' make; \ + make install PREFIX=mdocml-$(VERSION) ; \ + zip -r ../$@ mdocml-$(VERSION) ) + rm -rf .win64 -llib-llibmandoc.ln: $(MANDOCLNS) - $(LINT) -Clibmandoc $(MANDOCLNS) +mdocml-macosx.zip: $(SRCS) + mkdir -p .macosx/mdocml-$(VERSION)/ + $(INSTALL_SOURCE) $(SRCS) .macosx + ( cd .macosx; \ + CFLAGS="-arch i386 -arch x86_64 -arch ppc" LDFLAGS="-arch i386 -arch x86_64 -arch ppc" make; \ + make install PREFIX=mdocml-$(VERSION) ; \ + zip -r ../$@ mdocml-$(VERSION) ) + rm -rf .macosx -llib-llibroff.ln: $(ROFFLNS) - $(LINT) -Clibroff $(ROFFLNS) - -llib-lmandoc.ln: $(MAINLNS) llib-llibmdoc.ln llib-llibman.ln llib-llibmandoc.ln llib-llibroff.ln - $(LINT) -Cmandoc $(MAINLNS) llib-llibmdoc.ln llib-llibman.ln llib-llibmandoc.ln llib-llibroff.ln - -libmdoc.a: $(MDOCOBJS) - $(AR) rs $@ $(MDOCOBJS) - -libman.a: $(MANOBJS) - $(AR) rs $@ $(MANOBJS) - -libmandoc.a: $(MANDOCOBJS) - $(AR) rs $@ $(MANDOCOBJS) - -libroff.a: $(ROFFOBJS) - $(AR) rs $@ $(ROFFOBJS) - -mandoc: $(MAINOBJS) libroff.a libmdoc.a libman.a libmandoc.a - $(CC) $(CFLAGS) -o $@ $(MAINOBJS) libroff.a libmdoc.a libman.a libmandoc.a - -.sgml.html: - validate --warn $< - sed -e "s!@VERSION@!$(VERSION)!" -e "s!@VDATE@!$(VDATE)!" $< > $@ - -.1.1.txt .3.3.txt .7.7.txt: - ./mandoc -Tascii -Wall,stop $< | col -b > $@ - -.1.1.sgml .3.3.sgml .7.7.sgml: - ./mandoc -Thtml -Wall,stop -Ostyle=style.css,man=%N.%S.html,includes=%I.html $< > $@ - -.1.1.ps .3.3.ps .7.7.ps: - ./mandoc -Tps -Wall,stop $< > $@ - -.1.1.xhtml .3.3.xhtml .7.7.xhtml: - ./mandoc -Txhtml -Wall,stop -Ostyle=style.css,man=%N.%S.xhtml,includes=%I.html $< > $@ - -.1.1.pdf .3.3.pdf .7.7.pdf: - ./mandoc -Tpdf -Wall,stop $< > $@ - -.tar.gz.md5: - md5 $< > $@ - -.h.h.html: - highlight -I $< >$@ +index.html: $(INDEX_OBJS) config.h: config.h.pre config.h.post rm -f config.log ( cat config.h.pre; \ - echo; \ - if $(CC) $(CFLAGS) -Werror -c test-strlcat.c >> config.log 2>&1; then \ + echo; \ + if $(CC) $(CFLAGS) -Werror -o test-fgetln test-fgetln.c >> config.log 2>&1; then \ + echo '#define HAVE_FGETLN'; \ + rm test-fgetln; \ + fi; \ + if $(CC) $(CFLAGS) -Werror -o test-strptime test-strptime.c >> config.log 2>&1; then \ + echo '#define HAVE_STRPTIME'; \ + rm test-strptime; \ + fi; \ + if $(CC) $(CFLAGS) -Werror -o test-getsubopt test-getsubopt.c >> config.log 2>&1; then \ + echo '#define HAVE_GETSUBOPT'; \ + rm test-getsubopt; \ + fi; \ + if $(CC) $(CFLAGS) -Werror -o test-strlcat test-strlcat.c >> config.log 2>&1; then \ echo '#define HAVE_STRLCAT'; \ - rm test-strlcat.o; \ - fi; \ - if $(CC) $(CFLAGS) -Werror -c test-strlcpy.c >> config.log 2>&1; then \ + rm test-strlcat; \ + fi; \ + if $(CC) $(CFLAGS) -Werror -o test-mmap test-mmap.c >> config.log 2>&1; then \ + echo '#define HAVE_MMAP'; \ + rm test-mmap; \ + fi; \ + if $(CC) $(CFLAGS) -Werror -o test-strlcpy test-strlcpy.c >> config.log 2>&1; then \ echo '#define HAVE_STRLCPY'; \ - rm test-strlcpy.o; \ - fi; \ - echo; \ - cat config.h.post \ + rm test-strlcpy; \ + fi; \ + echo; \ + cat config.h.post \ ) > $@ + +.h.h.html: + highlight -I $< >$@ + +.1.1.txt .3.3.txt .7.7.txt .8.8.txt: + ./mandoc -Tascii -Wall,stop $< | col -b >$@ + +.1.1.html .3.3.html .7.7.html .8.8.html: + ./mandoc -Thtml -Wall,stop -Ostyle=style.css,man=%N.%S.html,includes=%I.html $< >$@ + +.1.1.ps .3.3.ps .7.7.ps .8.8.ps: + ./mandoc -Tps -Wall,stop $< >$@ + +.1.1.xhtml .3.3.xhtml .7.7.xhtml .8.8.xhtml: + ./mandoc -Txhtml -Wall,stop -Ostyle=style.css,man=%N.%S.xhtml,includes=%I.html $< >$@ + +.1.1.pdf .3.3.pdf .7.7.pdf .8.8.pdf: + ./mandoc -Tpdf -Wall,stop $< >$@ + +.sgml.html: + validate --warn $< + sed -e "s!@VERSION@!$(VERSION)!" -e "s!@VDATE@!$(VDATE)!" $< >$@ diff --git a/external/bsd/mdocml/dist/apropos.1 b/external/bsd/mdocml/dist/apropos.1 new file mode 100644 index 000000000..e4bd6556e --- /dev/null +++ b/external/bsd/mdocml/dist/apropos.1 @@ -0,0 +1,312 @@ +.\" $Vendor-Id: apropos.1,v 1.16 2011/12/25 19:35:44 kristaps Exp $ +.\" +.\" Copyright (c) 2011 Kristaps Dzonsons +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd December 25, 2011 +.Dt APROPOS 1 +.Os +.Sh NAME +.Nm apropos +.Nd search manual page databases +.Sh SYNOPSIS +.Nm +.Op Fl C Ar file +.Op Fl M Ar manpath +.Op Fl m Ar manpath +.Op Fl S Ar arch +.Op Fl s Ar section +.Ar expression ... +.Sh DESCRIPTION +The +.Nm +utility queries manual page databases generated by +.Xr mandocdb 8 , +evaluating on +.Ar expression +for each file in each database. +.Pp +By default, +.Nm +searches for +.Xr mandocdb 8 +databases in the default paths stipulated by +.Xr man 1 , +parses terms as case-sensitive regular expressions +.Pq the Li \&~ operator +over manual names and descriptions +.Pq the Li \&Nm No and Li \&Nd No macro keys . +Multiple terms imply pairwise +.Fl o . +.Pp +Its arguments are as follows: +.Bl -tag -width Ds +.It Fl C Ar file +Specify an alternative configuration +.Ar file +in +.Xr man.conf 5 +format. +.It Fl M Ar manpath +Use the colon-separated path instead of the default list of paths +searched for +.Xr mandocdb 8 +databases. +Invalid paths, or paths without manual databases, are ignored. +.It Fl m Ar manpath +Prepend the colon-separated paths to the list of paths searched +for +.Xr mandocdb 8 +databases. +Invalid paths, or paths without manual databases, are ignored. +.It Fl S Ar arch +Search only for a particular architecture. +.It Fl s Ar cat +Search only for a manual section. +See +.Xr man 1 +for a listing of manual sections. +.El +.Pp +An +.Ar expression +consists of search terms joined by logical operators +.Fl a +.Pq and +and +.Fl o +.Pq or . +The +.Fl a +operator has precedence over +.Fl o +and both are evaluated left-to-right. +.Bl -tag -width Ds +.It \&( Ar expr No \&) +True if the subexpression +.Ar expr +is true. +.It Ar expr1 Fl a Ar expr2 +True if both +.Ar expr1 +and +.Ar expr2 +are true (logical +.Qq and ) . +.It Ar expr1 Oo Fl o Oc Ar expr2 +True if +.Ar expr1 +and/or +.Ar expr2 +evaluate to true (logical +.Qq or ) . +.It Ar term +True if +.Ar term +is satisfied. +This has syntax +.Li [key[,key]*(=~)]?val , +where operand +.Cm key +is an +.Xr mdoc 7 +macro to query and +.Cm val +is its value. +See +.Sx Macro Keys +for a list of available keys. +Operator +.Li \&= +evaluates a substring, while +.Li \&~ +evaluates a regular expression. +.It Fl i Ar term +If +.Ar term +is a regular expression, it +is evaluated case-insensitively. +Has no effect on substring terms. +.El +.Pp +Results are sorted by manual title, with output formatted as +.Pp +.D1 title(sec) \- description +.Pp +Where +.Qq title +is the manual's title (note multiple manual names may exist for one +title), +.Qq sec +is the manual section, and +.Qq description +is the manual's short description. +If an architecture is specified for the manual, it is displayed as +.Pp +.D1 title(cat/arch) \- description +.Pp +Resulting manuals may be accessed as +.Pp +.Dl $ man \-s sec title +.Pp +If an architecture is specified in the output, use +.Pp +.Dl $ man \-s sec \-S arch title +.Ss Macro Keys +Queries evaluate over a subset of +.Xr mdoc 7 +macros indexed by +.Xr mandocdb 8 . +In addition to the macro keys listed below, the special key +.Cm any +may be used to match any available macro key. +.Pp +Names and description: +.Bl -column "xLix" description -offset indent -compact +.It Li \&Nm Ta manual name +.It Li \&Nd Ta one-line manual description +.El +.Pp +Sections and cross references: +.Bl -column "xLix" description -offset indent -compact +.It Li \&Sh Ta section header (excluding standard sections) +.It Li \&Ss Ta subsection header +.It Li \&Xr Ta cross reference to another manual page +.It Li \&Rs Ta bibliographic reference +.El +.Pp +Semantic markup for command line utilities: +.Bl -column "xLix" description -offset indent -compact +.It Li \&Fl Ta command line options (flags) +.It Li \&Cm Ta command modifier +.It Li \&Ar Ta command argument +.It Li \&Ic Ta internal or interactive command +.It Li \&Ev Ta environmental variable +.It Li \&Pa Ta file system path +.El +.Pp +Semantic markup for function libraries: +.Bl -column "xLix" description -offset indent -compact +.It Li \&Lb Ta function library name +.It Li \&In Ta include file +.It Li \&Ft Ta function return type +.It Li \&Fn Ta function name +.It Li \&Fa Ta function argument type and name +.It Li \&Vt Ta variable type +.It Li \&Va Ta variable name +.It Li \&Dv Ta defined variable or preprocessor constant +.It Li \&Er Ta error constant +.It Li \&Ev Ta environmental variable +.El +.Pp +Various semantic markup: +.Bl -column "xLix" description -offset indent -compact +.It Li \&An Ta author name +.It Li \&Lk Ta hyperlink +.It Li \&Mt Ta Do mailto Dc hyperlink +.It Li \&Cd Ta kernel configuration declaration +.It Li \&Ms Ta mathematical symbol +.It Li \&Tn Ta tradename +.El +.Pp +Physical markup: +.Bl -column "xLix" description -offset indent -compact +.It Li \&Em Ta italic font or underline +.It Li \&Sy Ta boldface font +.It Li \&Li Ta typewriter font +.El +.Pp +Text production: +.Bl -column "xLix" description -offset indent -compact +.It Li \&St Ta reference to a standards document +.It Li \&At Ta At No version reference +.It Li \&Bx Ta Bx No version reference +.It Li \&Bsx Ta Bsx No version reference +.It Li \&Nx Ta Nx No version reference +.It Li \&Fx Ta Fx No version reference +.It Li \&Ox Ta Ox No version reference +.It Li \&Dx Ta Dx No version reference +.El +.Sh ENVIRONMENT +.Bl -tag -width Ds +.It Ev MANPATH +Colon-separated paths modifying the default list of paths searched for +manual databases. +Invalid paths, or paths without manual databases, are ignored. +Overridden by +.Fl M . +If +.Ev MANPATH +begins with a +.Sq \&: , +it is appended to the default list; +else if it ends with +.Sq \&: , +it is prepended to the default list; else if it contains +.Sq \&:: , +the default list is inserted between the colons. +If none of these conditions are met, it overrides the default list. +.El +.Sh FILES +.Bl -tag -width "/etc/man.conf" -compact +.It Pa whatis.db +name of the +.Xr mandocdb 8 +keyword database +.It Pa whatis.index +name of the +.Xr mandocdb 8 +filename database +.It Pa /etc/man.conf +default +.Xr man 1 +configuration file +.El +.Sh EXIT STATUS +.Ex -std +.Sh EXAMPLES +Search for +.Qq mdoc +as a substring and regular expression +within each manual name and description: +.Pp +.Dl $ apropos mdoc +.Dl $ apropos ~^mdoc$ +.Pp +Include matches for +.Qq roff +and +.Qq man +for the regular expression case: +.Pp +.Dl $ apropos ~^mdoc$ roff man +.Dl $ apropos ~^mdoc$ \-o roff \-o man +.Pp +Search for +.Qq optind +and +.Qq optarg +as variable names in the library category: +.Pp +.Dl $ apropos \-s 3 Va~^optind \-a Va~^optarg$ +.Sh SEE ALSO +.Xr man 1 , +.Xr re_format 7 , +.Xr mandocdb 8 +.Sh AUTHORS +The +.Nm +utility was written by +.An Kristaps Dzonsons , +.Mt kristaps@bsd.lv . diff --git a/external/bsd/mdocml/dist/apropos.c b/external/bsd/mdocml/dist/apropos.c new file mode 100644 index 000000000..df9d86426 --- /dev/null +++ b/external/bsd/mdocml/dist/apropos.c @@ -0,0 +1,157 @@ +/* $Vendor-Id: apropos.c,v 1.25 2011/12/31 18:47:52 kristaps Exp $ */ +/* + * Copyright (c) 2011 Kristaps Dzonsons + * Copyright (c) 2011 Ingo Schwarze + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include + +#include "apropos_db.h" +#include "mandoc.h" +#include "manpath.h" + +static int cmp(const void *, const void *); +static void list(struct res *, size_t, void *); +static void usage(void); + +static char *progname; + +int +main(int argc, char *argv[]) +{ + int ch, rc, whatis; + struct manpaths paths; + size_t terms; + struct opts opts; + struct expr *e; + char *defpaths, *auxpaths; + char *conf_file; + extern int optind; + extern char *optarg; + + progname = strrchr(argv[0], '/'); + if (progname == NULL) + progname = argv[0]; + else + ++progname; + + whatis = 0 == strncmp(progname, "whatis", 6); + + memset(&paths, 0, sizeof(struct manpaths)); + memset(&opts, 0, sizeof(struct opts)); + + auxpaths = defpaths = NULL; + conf_file = NULL; + e = NULL; + + while (-1 != (ch = getopt(argc, argv, "C:M:m:S:s:"))) + switch (ch) { + case ('C'): + conf_file = optarg; + break; + case ('M'): + defpaths = optarg; + break; + case ('m'): + auxpaths = optarg; + break; + case ('S'): + opts.arch = optarg; + break; + case ('s'): + opts.cat = optarg; + break; + default: + usage(); + return(EXIT_FAILURE); + } + + argc -= optind; + argv += optind; + + if (0 == argc) + return(EXIT_SUCCESS); + + rc = 0; + + manpath_parse(&paths, conf_file, defpaths, auxpaths); + + e = whatis ? termcomp(argc, argv, &terms) : + exprcomp(argc, argv, &terms); + + if (NULL == e) { + fprintf(stderr, "%s: Bad expression\n", progname); + goto out; + } + + rc = apropos_search + (paths.sz, paths.paths, + &opts, e, terms, NULL, list); + + if (0 == rc) + fprintf(stderr, "%s: Error reading " + "manual database\n", progname); + +out: + manpath_free(&paths); + exprfree(e); + + return(rc ? EXIT_SUCCESS : EXIT_FAILURE); +} + +/* ARGSUSED */ +static void +list(struct res *res, size_t sz, void *arg) +{ + int i; + + qsort(res, sz, sizeof(struct res), cmp); + + for (i = 0; i < (int)sz; i++) + printf("%s(%s%s%s) - %.70s\n", res[i].title, + res[i].cat, + *res[i].arch ? "/" : "", + *res[i].arch ? res[i].arch : "", + res[i].desc); +} + +static int +cmp(const void *p1, const void *p2) +{ + + return(strcasecmp(((const struct res *)p1)->title, + ((const struct res *)p2)->title)); +} + +static void +usage(void) +{ + + fprintf(stderr, "usage: %s " + "[-C file] " + "[-M manpath] " + "[-m manpath] " + "[-S arch] " + "[-s section] " + "expression ...\n", + progname); +} diff --git a/external/bsd/mdocml/dist/apropos_db.c b/external/bsd/mdocml/dist/apropos_db.c new file mode 100644 index 000000000..f79e0eede --- /dev/null +++ b/external/bsd/mdocml/dist/apropos_db.c @@ -0,0 +1,899 @@ +/* $Vendor-Id: apropos_db.c,v 1.28 2011/12/25 14:58:39 schwarze Exp $ */ +/* + * Copyright (c) 2011 Kristaps Dzonsons + * Copyright (c) 2011 Ingo Schwarze + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(__linux__) +# include +# include +#elif defined(__APPLE__) +# include +# include +#else +# include +#endif + +#include "mandocdb.h" +#include "apropos_db.h" +#include "mandoc.h" + +struct rec { + struct res res; /* resulting record info */ + /* + * Maintain a binary tree for checking the uniqueness of `rec' + * when adding elements to the results array. + * Since the results array is dynamic, use offset in the array + * instead of a pointer to the structure. + */ + int lhs; + int rhs; + int matched; /* expression is true */ + int *matches; /* partial truth evaluations */ +}; + +struct expr { + int regex; /* is regex? */ + int index; /* index in match array */ + uint64_t mask; /* type-mask */ + int and; /* is rhs of logical AND? */ + char *v; /* search value */ + regex_t re; /* compiled re, if regex */ + struct expr *next; /* next in sequence */ + struct expr *subexpr; +}; + +struct type { + uint64_t mask; + const char *name; +}; + +struct rectree { + struct rec *node; /* record array for dir tree */ + int len; /* length of record array */ +}; + +static const struct type types[] = { + { TYPE_An, "An" }, + { TYPE_Ar, "Ar" }, + { TYPE_At, "At" }, + { TYPE_Bsx, "Bsx" }, + { TYPE_Bx, "Bx" }, + { TYPE_Cd, "Cd" }, + { TYPE_Cm, "Cm" }, + { TYPE_Dv, "Dv" }, + { TYPE_Dx, "Dx" }, + { TYPE_Em, "Em" }, + { TYPE_Er, "Er" }, + { TYPE_Ev, "Ev" }, + { TYPE_Fa, "Fa" }, + { TYPE_Fl, "Fl" }, + { TYPE_Fn, "Fn" }, + { TYPE_Fn, "Fo" }, + { TYPE_Ft, "Ft" }, + { TYPE_Fx, "Fx" }, + { TYPE_Ic, "Ic" }, + { TYPE_In, "In" }, + { TYPE_Lb, "Lb" }, + { TYPE_Li, "Li" }, + { TYPE_Lk, "Lk" }, + { TYPE_Ms, "Ms" }, + { TYPE_Mt, "Mt" }, + { TYPE_Nd, "Nd" }, + { TYPE_Nm, "Nm" }, + { TYPE_Nx, "Nx" }, + { TYPE_Ox, "Ox" }, + { TYPE_Pa, "Pa" }, + { TYPE_Rs, "Rs" }, + { TYPE_Sh, "Sh" }, + { TYPE_Ss, "Ss" }, + { TYPE_St, "St" }, + { TYPE_Sy, "Sy" }, + { TYPE_Tn, "Tn" }, + { TYPE_Va, "Va" }, + { TYPE_Va, "Vt" }, + { TYPE_Xr, "Xr" }, + { UINT64_MAX, "any" }, + { 0, NULL } +}; + +static DB *btree_open(void); +static int btree_read(const DBT *, const DBT *, + const struct mchars *, + uint64_t *, recno_t *, char **); +static int expreval(const struct expr *, int *); +static void exprexec(const struct expr *, + const char *, uint64_t, struct rec *); +static int exprmark(const struct expr *, + const char *, uint64_t, int *); +static struct expr *exprexpr(int, char *[], int *, int *, size_t *); +static struct expr *exprterm(char *, int); +static DB *index_open(void); +static int index_read(const DBT *, const DBT *, int, + const struct mchars *, struct rec *); +static void norm_string(const char *, + const struct mchars *, char **); +static size_t norm_utf8(unsigned int, char[7]); +static void recfree(struct rec *); +static int single_search(struct rectree *, const struct opts *, + const struct expr *, size_t terms, + struct mchars *, int); + +/* + * Open the keyword mandoc-db database. + */ +static DB * +btree_open(void) +{ + BTREEINFO info; + DB *db; + + memset(&info, 0, sizeof(BTREEINFO)); + info.flags = R_DUP; + + db = dbopen(MANDOC_DB, O_RDONLY, 0, DB_BTREE, &info); + if (NULL != db) + return(db); + + return(NULL); +} + +/* + * Read a keyword from the database and normalise it. + * Return 0 if the database is insane, else 1. + */ +static int +btree_read(const DBT *k, const DBT *v, const struct mchars *mc, + uint64_t *mask, recno_t *rec, char **buf) +{ + uint64_t vbuf[2]; + + /* Are our sizes sane? */ + if (k->size < 2 || sizeof(vbuf) != v->size) + return(0); + + /* Is our string nil-terminated? */ + if ('\0' != ((const char *)k->data)[(int)k->size - 1]) + return(0); + + norm_string((const char *)k->data, mc, buf); + memcpy(vbuf, v->data, v->size); + *mask = betoh64(vbuf[0]); + *rec = betoh64(vbuf[1]); + return(1); +} + +/* + * Take a Unicode codepoint and produce its UTF-8 encoding. + * This isn't the best way to do this, but it works. + * The magic numbers are from the UTF-8 packaging. + * They're not as scary as they seem: read the UTF-8 spec for details. + */ +static size_t +norm_utf8(unsigned int cp, char out[7]) +{ + int rc; + + rc = 0; + + if (cp <= 0x0000007F) { + rc = 1; + out[0] = (char)cp; + } else if (cp <= 0x000007FF) { + rc = 2; + out[0] = (cp >> 6 & 31) | 192; + out[1] = (cp & 63) | 128; + } else if (cp <= 0x0000FFFF) { + rc = 3; + out[0] = (cp >> 12 & 15) | 224; + out[1] = (cp >> 6 & 63) | 128; + out[2] = (cp & 63) | 128; + } else if (cp <= 0x001FFFFF) { + rc = 4; + out[0] = (cp >> 18 & 7) | 240; + out[1] = (cp >> 12 & 63) | 128; + out[2] = (cp >> 6 & 63) | 128; + out[3] = (cp & 63) | 128; + } else if (cp <= 0x03FFFFFF) { + rc = 5; + out[0] = (cp >> 24 & 3) | 248; + out[1] = (cp >> 18 & 63) | 128; + out[2] = (cp >> 12 & 63) | 128; + out[3] = (cp >> 6 & 63) | 128; + out[4] = (cp & 63) | 128; + } else if (cp <= 0x7FFFFFFF) { + rc = 6; + out[0] = (cp >> 30 & 1) | 252; + out[1] = (cp >> 24 & 63) | 128; + out[2] = (cp >> 18 & 63) | 128; + out[3] = (cp >> 12 & 63) | 128; + out[4] = (cp >> 6 & 63) | 128; + out[5] = (cp & 63) | 128; + } else + return(0); + + out[rc] = '\0'; + return((size_t)rc); +} + +/* + * Normalise strings from the index and database. + * These strings are escaped as defined by mandoc_char(7) along with + * other goop in mandoc.h (e.g., soft hyphens). + * This function normalises these into a nice UTF-8 string. + * Returns 0 if the database is fucked. + */ +static void +norm_string(const char *val, const struct mchars *mc, char **buf) +{ + size_t sz, bsz; + char utfbuf[7]; + const char *seq, *cpp; + int len, u, pos; + enum mandoc_esc esc; + static const char res[] = { '\\', '\t', + ASCII_NBRSP, ASCII_HYPH, '\0' }; + + /* Pre-allocate by the length of the input */ + + bsz = strlen(val) + 1; + *buf = mandoc_realloc(*buf, bsz); + pos = 0; + + while ('\0' != *val) { + /* + * Halt on the first escape sequence. + * This also halts on the end of string, in which case + * we just copy, fallthrough, and exit the loop. + */ + if ((sz = strcspn(val, res)) > 0) { + memcpy(&(*buf)[pos], val, sz); + pos += (int)sz; + val += (int)sz; + } + + if (ASCII_HYPH == *val) { + (*buf)[pos++] = '-'; + val++; + continue; + } else if ('\t' == *val || ASCII_NBRSP == *val) { + (*buf)[pos++] = ' '; + val++; + continue; + } else if ('\\' != *val) + break; + + /* Read past the slash. */ + + val++; + u = 0; + + /* + * Parse the escape sequence and see if it's a + * predefined character or special character. + */ + + esc = mandoc_escape(&val, &seq, &len); + if (ESCAPE_ERROR == esc) + break; + + /* + * XXX - this just does UTF-8, but we need to know + * beforehand whether we should do text substitution. + */ + + switch (esc) { + case (ESCAPE_SPECIAL): + if (0 != (u = mchars_spec2cp(mc, seq, len))) + break; + /* FALLTHROUGH */ + default: + continue; + } + + /* + * If we have a Unicode codepoint, try to convert that + * to a UTF-8 byte string. + */ + + cpp = utfbuf; + if (0 == (sz = norm_utf8(u, utfbuf))) + continue; + + /* Copy the rendered glyph into the stream. */ + + sz = strlen(cpp); + bsz += sz; + + *buf = mandoc_realloc(*buf, bsz); + + memcpy(&(*buf)[pos], cpp, sz); + pos += (int)sz; + } + + (*buf)[pos] = '\0'; +} + +/* + * Open the filename-index mandoc-db database. + * Returns NULL if opening failed. + */ +static DB * +index_open(void) +{ + DB *db; + + db = dbopen(MANDOC_IDX, O_RDONLY, 0, DB_RECNO, NULL); + if (NULL != db) + return(db); + + return(NULL); +} + +/* + * Safely unpack from an index file record into the structure. + * Returns 1 if an entry was unpacked, 0 if the database is insane. + */ +static int +index_read(const DBT *key, const DBT *val, int index, + const struct mchars *mc, struct rec *rec) +{ + size_t left; + char *np, *cp; + char type; + +#define INDEX_BREAD(_dst) \ + do { \ + if (NULL == (np = memchr(cp, '\0', left))) \ + return(0); \ + norm_string(cp, mc, &(_dst)); \ + left -= (np - cp) + 1; \ + cp = np + 1; \ + } while (/* CONSTCOND */ 0) + + if (0 == (left = val->size)) + return(0); + + cp = val->data; + assert(sizeof(recno_t) == key->size); + memcpy(&rec->res.rec, key->data, key->size); + rec->res.volume = index; + + if ('d' == (type = *cp++)) + rec->res.type = RESTYPE_MDOC; + else if ('a' == type) + rec->res.type = RESTYPE_MAN; + else if ('c' == type) + rec->res.type = RESTYPE_CAT; + else + return(0); + + left--; + INDEX_BREAD(rec->res.file); + INDEX_BREAD(rec->res.cat); + INDEX_BREAD(rec->res.title); + INDEX_BREAD(rec->res.arch); + INDEX_BREAD(rec->res.desc); + return(1); +} + +/* + * Search mandocdb databases in paths for expression "expr". + * Filter out by "opts". + * Call "res" with the results, which may be zero. + * Return 0 if there was a database error, else return 1. + */ +int +apropos_search(int pathsz, char **paths, const struct opts *opts, + const struct expr *expr, size_t terms, void *arg, + void (*res)(struct res *, size_t, void *)) +{ + struct rectree tree; + struct mchars *mc; + struct res *ress; + int i, mlen, rc; + + memset(&tree, 0, sizeof(struct rectree)); + + rc = 0; + mc = mchars_alloc(); + + /* + * Main loop. Change into the directory containing manpage + * databases. Run our expession over each database in the set. + */ + + for (i = 0; i < pathsz; i++) { + if (chdir(paths[i])) + continue; + if ( ! single_search(&tree, opts, expr, terms, mc, i)) + goto out; + } + + /* + * Count matching files, transfer to a "clean" array, then feed + * them to the output handler. + */ + + for (mlen = i = 0; i < tree.len; i++) + if (tree.node[i].matched) + mlen++; + + ress = mandoc_malloc(mlen * sizeof(struct res)); + + for (mlen = i = 0; i < tree.len; i++) + if (tree.node[i].matched) + memcpy(&ress[mlen++], &tree.node[i].res, + sizeof(struct res)); + + (*res)(ress, mlen, arg); + free(ress); + + rc = 1; +out: + for (i = 0; i < tree.len; i++) + recfree(&tree.node[i]); + + free(tree.node); + mchars_free(mc); + return(rc); +} + +static int +single_search(struct rectree *tree, const struct opts *opts, + const struct expr *expr, size_t terms, + struct mchars *mc, int vol) +{ + int root, leaf, ch; + DBT key, val; + DB *btree, *idx; + char *buf; + struct rec *rs; + struct rec r; + uint64_t mask; + recno_t rec; + + root = -1; + leaf = -1; + btree = NULL; + idx = NULL; + buf = NULL; + rs = tree->node; + + memset(&r, 0, sizeof(struct rec)); + + if (NULL == (btree = btree_open())) + return(1); + + if (NULL == (idx = index_open())) { + (*btree->close)(btree); + return(1); + } + + while (0 == (ch = (*btree->seq)(btree, &key, &val, R_NEXT))) { + if ( ! btree_read(&key, &val, mc, &mask, &rec, &buf)) + break; + + /* + * See if this keyword record matches any of the + * expressions we have stored. + */ + if ( ! exprmark(expr, buf, mask, NULL)) + continue; + + /* + * O(log n) scan for prior records. Since a record + * number is unbounded, this has decent performance over + * a complex hash function. + */ + + for (leaf = root; leaf >= 0; ) + if (rec > rs[leaf].res.rec && + rs[leaf].rhs >= 0) + leaf = rs[leaf].rhs; + else if (rec < rs[leaf].res.rec && + rs[leaf].lhs >= 0) + leaf = rs[leaf].lhs; + else + break; + + /* + * If we find a record, see if it has already evaluated + * to true. If it has, great, just keep going. If not, + * try to evaluate it now and continue anyway. + */ + + if (leaf >= 0 && rs[leaf].res.rec == rec) { + if (0 == rs[leaf].matched) + exprexec(expr, buf, mask, &rs[leaf]); + continue; + } + + /* + * We have a new file to examine. + * Extract the manpage's metadata from the index + * database, then begin partial evaluation. + */ + + key.data = &rec; + key.size = sizeof(recno_t); + + if (0 != (*idx->get)(idx, &key, &val, 0)) + break; + + r.lhs = r.rhs = -1; + if ( ! index_read(&key, &val, vol, mc, &r)) + break; + + /* XXX: this should be elsewhere, I guess? */ + + if (opts->cat && strcasecmp(opts->cat, r.res.cat)) + continue; + + if (opts->arch && *r.res.arch) + if (strcasecmp(opts->arch, r.res.arch)) + continue; + + tree->node = rs = mandoc_realloc + (rs, (tree->len + 1) * sizeof(struct rec)); + + memcpy(&rs[tree->len], &r, sizeof(struct rec)); + memset(&r, 0, sizeof(struct rec)); + rs[tree->len].matches = + mandoc_calloc(terms, sizeof(int)); + + exprexec(expr, buf, mask, &rs[tree->len]); + + /* Append to our tree. */ + + if (leaf >= 0) { + if (rec > rs[leaf].res.rec) + rs[leaf].rhs = tree->len; + else + rs[leaf].lhs = tree->len; + } else + root = tree->len; + + tree->len++; + } + + (*btree->close)(btree); + (*idx->close)(idx); + + free(buf); + recfree(&r); + return(1 == ch); +} + +static void +recfree(struct rec *rec) +{ + + free(rec->res.file); + free(rec->res.cat); + free(rec->res.title); + free(rec->res.arch); + free(rec->res.desc); + + free(rec->matches); +} + +/* + * Compile a list of straight-up terms. + * The arguments are re-written into ~[[:<:]]term[[:>:]], or "term" + * surrounded by word boundaries, then pumped through exprterm(). + * Terms are case-insensitive. + * This emulates whatis(1) behaviour. + */ +struct expr * +termcomp(int argc, char *argv[], size_t *tt) +{ + char *buf; + int pos; + struct expr *e, *next; + size_t sz; + + buf = NULL; + e = NULL; + *tt = 0; + + for (pos = argc - 1; pos >= 0; pos--) { + sz = strlen(argv[pos]) + 18; + buf = mandoc_realloc(buf, sz); + strlcpy(buf, "Nm~[[:<:]]", sz); + strlcat(buf, argv[pos], sz); + strlcat(buf, "[[:>:]]", sz); + if (NULL == (next = exprterm(buf, 0))) { + free(buf); + exprfree(e); + return(NULL); + } + next->next = e; + e = next; + (*tt)++; + } + + free(buf); + return(e); +} + +/* + * Compile a sequence of logical expressions. + * See apropos.1 for a grammar of this sequence. + */ +struct expr * +exprcomp(int argc, char *argv[], size_t *tt) +{ + int pos, lvl; + struct expr *e; + + pos = lvl = 0; + *tt = 0; + + e = exprexpr(argc, argv, &pos, &lvl, tt); + + if (0 == lvl && pos >= argc) + return(e); + + exprfree(e); + return(NULL); +} + +/* + * Compile an array of tokens into an expression. + * An informal expression grammar is defined in apropos(1). + * Return NULL if we fail doing so. All memory will be cleaned up. + * Return the root of the expression sequence if alright. + */ +static struct expr * +exprexpr(int argc, char *argv[], int *pos, int *lvl, size_t *tt) +{ + struct expr *e, *first, *next; + int log; + + first = next = NULL; + + for ( ; *pos < argc; (*pos)++) { + e = next; + + /* + * Close out a subexpression. + */ + + if (NULL != e && 0 == strcmp(")", argv[*pos])) { + if (--(*lvl) < 0) + goto err; + break; + } + + /* + * Small note: if we're just starting, don't let "-a" + * and "-o" be considered logical operators: they're + * just tokens unless pairwise joining, in which case we + * record their existence (or assume "OR"). + */ + log = 0; + + if (NULL != e && 0 == strcmp("-a", argv[*pos])) + log = 1; + else if (NULL != e && 0 == strcmp("-o", argv[*pos])) + log = 2; + + if (log > 0 && ++(*pos) >= argc) + goto err; + + /* + * Now we parse the term part. This can begin with + * "-i", in which case the expression is case + * insensitive. + */ + + if (0 == strcmp("(", argv[*pos])) { + ++(*pos); + ++(*lvl); + next = mandoc_calloc(1, sizeof(struct expr)); + next->subexpr = exprexpr(argc, argv, pos, lvl, tt); + if (NULL == next->subexpr) { + free(next); + next = NULL; + } + } else if (0 == strcmp("-i", argv[*pos])) { + if (++(*pos) >= argc) + goto err; + next = exprterm(argv[*pos], 0); + } else + next = exprterm(argv[*pos], 1); + + if (NULL == next) + goto err; + + next->and = log == 1; + next->index = (int)(*tt)++; + + /* Append to our chain of expressions. */ + + if (NULL == first) { + assert(NULL == e); + first = next; + } else { + assert(NULL != e); + e->next = next; + } + } + + return(first); +err: + exprfree(first); + return(NULL); +} + +/* + * Parse a terminal expression with the grammar as defined in + * apropos(1). + * Return NULL if we fail the parse. + */ +static struct expr * +exprterm(char *buf, int cs) +{ + struct expr e; + struct expr *p; + char *key; + int i; + + memset(&e, 0, sizeof(struct expr)); + + /* Choose regex or substring match. */ + + if (NULL == (e.v = strpbrk(buf, "=~"))) { + e.regex = 0; + e.v = buf; + } else { + e.regex = '~' == *e.v; + *e.v++ = '\0'; + } + + /* Determine the record types to search for. */ + + e.mask = 0; + if (buf < e.v) { + while (NULL != (key = strsep(&buf, ","))) { + i = 0; + while (types[i].mask && + strcmp(types[i].name, key)) + i++; + e.mask |= types[i].mask; + } + } + if (0 == e.mask) + e.mask = TYPE_Nm | TYPE_Nd; + + if (e.regex) { + i = REG_EXTENDED | REG_NOSUB | (cs ? 0 : REG_ICASE); + if (regcomp(&e.re, e.v, i)) + return(NULL); + } + + e.v = mandoc_strdup(e.v); + + p = mandoc_calloc(1, sizeof(struct expr)); + memcpy(p, &e, sizeof(struct expr)); + return(p); +} + +void +exprfree(struct expr *p) +{ + struct expr *pp; + + while (NULL != p) { + if (p->subexpr) + exprfree(p->subexpr); + if (p->regex) + regfree(&p->re); + free(p->v); + pp = p->next; + free(p); + p = pp; + } +} + +static int +exprmark(const struct expr *p, const char *cp, + uint64_t mask, int *ms) +{ + + for ( ; p; p = p->next) { + if (p->subexpr) { + if (exprmark(p->subexpr, cp, mask, ms)) + return(1); + continue; + } else if ( ! (mask & p->mask)) + continue; + + if (p->regex) { + if (regexec(&p->re, cp, 0, NULL, 0)) + continue; + } else if (NULL == strcasestr(cp, p->v)) + continue; + + if (NULL == ms) + return(1); + else + ms[p->index] = 1; + } + + return(0); +} + +static int +expreval(const struct expr *p, int *ms) +{ + int match; + + /* + * AND has precedence over OR. Analysis is left-right, though + * it doesn't matter because there are no side-effects. + * Thus, step through pairwise ANDs and accumulate their Boolean + * evaluation. If we encounter a single true AND collection or + * standalone term, the whole expression is true (by definition + * of OR). + */ + + for (match = 0; p && ! match; p = p->next) { + /* Evaluate a subexpression, if applicable. */ + if (p->subexpr && ! ms[p->index]) + ms[p->index] = expreval(p->subexpr, ms); + + match = ms[p->index]; + for ( ; p->next && p->next->and; p = p->next) { + /* Evaluate a subexpression, if applicable. */ + if (p->next->subexpr && ! ms[p->next->index]) + ms[p->next->index] = + expreval(p->next->subexpr, ms); + match = match && ms[p->next->index]; + } + } + + return(match); +} + +/* + * First, update the array of terms for which this expression evaluates + * to true. + * Second, logically evaluate all terms over the updated array of truth + * values. + * If this evaluates to true, mark the expression as satisfied. + */ +static void +exprexec(const struct expr *e, const char *cp, + uint64_t mask, struct rec *r) +{ + + assert(0 == r->matched); + exprmark(e, cp, mask, r->matches); + r->matched = expreval(e, r->matches); +} diff --git a/external/bsd/mdocml/dist/apropos_db.h b/external/bsd/mdocml/dist/apropos_db.h new file mode 100644 index 000000000..0fa5eb389 --- /dev/null +++ b/external/bsd/mdocml/dist/apropos_db.h @@ -0,0 +1,59 @@ +/* $Vendor-Id: apropos_db.h,v 1.11 2011/12/16 12:06:35 kristaps Exp $ */ +/* + * Copyright (c) 2011 Kristaps Dzonsons + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef APROPOS_H +#define APROPOS_H + +enum restype { + RESTYPE_MAN, /* man(7) file */ + RESTYPE_MDOC, /* mdoc(7) file */ + RESTYPE_CAT /* pre-formatted file */ +}; + +struct res { + enum restype type; /* input file type */ + char *file; /* file in file-system */ + char *cat; /* category (3p, 3, etc.) */ + char *title; /* title (FOO, etc.) */ + char *arch; /* arch (or empty string) */ + char *desc; /* description (from Nd) */ + unsigned int rec; /* record in index */ + /* + * The index volume. This indexes into the array of directories + * searched for manual page databases. + */ + unsigned int volume; +}; + +struct opts { + const char *arch; /* restrict to architecture */ + const char *cat; /* restrict to manual section */ +}; + +__BEGIN_DECLS + +struct expr; + +int apropos_search(int, char **, const struct opts *, + const struct expr *, size_t, void *, + void (*)(struct res *, size_t, void *)); +struct expr *exprcomp(int, char *[], size_t *); +void exprfree(struct expr *); +struct expr *termcomp(int, char *[], size_t *); + +__END_DECLS + +#endif /*!APROPOS_H*/ diff --git a/external/bsd/mdocml/dist/arch.c b/external/bsd/mdocml/dist/arch.c index 26f1962f4..2357c0808 100644 --- a/external/bsd/mdocml/dist/arch.c +++ b/external/bsd/mdocml/dist/arch.c @@ -1,4 +1,4 @@ -/* $Vendor-Id: arch.c,v 1.8 2010/06/19 20:46:27 kristaps Exp $ */ +/* $Vendor-Id: arch.c,v 1.9 2011/03/22 14:33:05 kristaps Exp $ */ /* * Copyright (c) 2009 Kristaps Dzonsons * @@ -22,6 +22,7 @@ #include #include +#include "mdoc.h" #include "mandoc.h" #include "libmdoc.h" diff --git a/external/bsd/mdocml/dist/arch.in b/external/bsd/mdocml/dist/arch.in index fd1cb6eb0..9d9553dcf 100644 --- a/external/bsd/mdocml/dist/arch.in +++ b/external/bsd/mdocml/dist/arch.in @@ -1,4 +1,4 @@ -/* $Vendor-Id: arch.in,v 1.10 2010/09/27 06:56:44 kristaps Exp $ */ +/* $Vendor-Id: arch.in,v 1.12 2012/01/28 14:02:17 joerg Exp $ */ /* * Copyright (c) 2009 Kristaps Dzonsons * @@ -26,31 +26,86 @@ * REMEMBER TO ADD NEW ARCHITECTURES TO MDOC.7! */ +LINE("acorn26", "Acorn26") +LINE("acorn32", "Acorn32") +LINE("algor", "Algor") LINE("alpha", "Alpha") LINE("amd64", "AMD64") LINE("amiga", "Amiga") +LINE("amigappc", "AmigaPPC") LINE("arc", "ARC") LINE("arm", "ARM") +LINE("arm26", "ARM26") +LINE("arm32", "ARM32") LINE("armish", "ARMISH") LINE("aviion", "AViiON") +LINE("atari", "ATARI") +LINE("beagle", "Beagle") +LINE("bebox", "BeBox") +LINE("cats", "cats") +LINE("cesfic", "CESFIC") +LINE("cobalt", "Cobalt") +LINE("dreamcast", "Dreamcast") +LINE("emips", "EMIPS") +LINE("evbarm", "evbARM") +LINE("evbmips", "evbMIPS") +LINE("evbppc", "evbPPC") +LINE("evbsh3", "evbSH3") +LINE("ews4800mips", "EWS4800MIPS") LINE("hp300", "HP300") +LINE("hp700", "HP700") +LINE("hpcarm", "HPCARM") +LINE("hpcmips", "HPCMIPS") +LINE("hpcsh", "HPCSH") LINE("hppa", "HPPA") LINE("hppa64", "HPPA64") +LINE("ia64", "ia64") LINE("i386", "i386") +LINE("ibmnws", "IBMNWS") +LINE("iyonix", "Iyonix") LINE("landisk", "LANDISK") LINE("loongson", "Loongson") +LINE("luna68k", "Luna68k") LINE("luna88k", "Luna88k") +LINE("m68k", "m68k") LINE("mac68k", "Mac68k") LINE("macppc", "MacPPC") +LINE("mips", "MIPS") LINE("mips64", "MIPS64") +LINE("mipsco", "MIPSCo") +LINE("mmeye", "mmEye") LINE("mvme68k", "MVME68k") LINE("mvme88k", "MVME88k") LINE("mvmeppc", "MVMEPPC") +LINE("netwinder", "NetWinder") +LINE("news68k", "NeWS68k") +LINE("newsmips", "NeWSMIPS") +LINE("next68k", "NeXT68k") +LINE("ofppc", "OFPPC") +LINE("palm", "Palm") +LINE("pc532", "PC532") +LINE("playstation2", "PlayStation2") LINE("pmax", "PMAX") +LINE("pmppc", "pmPPC") +LINE("powerpc", "PowerPC") +LINE("prep", "PReP") +LINE("rs6000", "RS6000") +LINE("sandpoint", "Sandpoint") +LINE("sbmips", "SBMIPS") LINE("sgi", "SGI") +LINE("sgimips", "SGIMIPS") +LINE("sh3", "SH3") +LINE("shark", "Shark") LINE("socppc", "SOCPPC") +LINE("solbourne", "Solbourne") LINE("sparc", "SPARC") LINE("sparc64", "SPARC64") +LINE("sun2", "Sun2") LINE("sun3", "Sun3") +LINE("tahoe", "Tahoe") LINE("vax", "VAX") +LINE("x68k", "X68k") +LINE("x86", "x86") +LINE("x86_64", "x86_64") +LINE("xen", "Xen") LINE("zaurus", "Zaurus") diff --git a/external/bsd/mdocml/dist/att.c b/external/bsd/mdocml/dist/att.c index 13c68bcb2..3c56a3cac 100644 --- a/external/bsd/mdocml/dist/att.c +++ b/external/bsd/mdocml/dist/att.c @@ -1,4 +1,4 @@ -/* $Vendor-Id: att.c,v 1.8 2010/06/19 20:46:27 kristaps Exp $ */ +/* $Vendor-Id: att.c,v 1.9 2011/03/22 14:33:05 kristaps Exp $ */ /* * Copyright (c) 2009 Kristaps Dzonsons * @@ -22,6 +22,7 @@ #include #include +#include "mdoc.h" #include "mandoc.h" #include "libmdoc.h" diff --git a/external/bsd/mdocml/dist/att.in b/external/bsd/mdocml/dist/att.in index 5dfcd8271..b807da02c 100644 --- a/external/bsd/mdocml/dist/att.in +++ b/external/bsd/mdocml/dist/att.in @@ -1,4 +1,4 @@ -/* $Vendor-Id: att.in,v 1.6 2010/06/19 20:46:27 kristaps Exp $ */ +/* $Vendor-Id: att.in,v 1.8 2011/07/31 17:30:33 schwarze Exp $ */ /* * Copyright (c) 2009 Kristaps Dzonsons * @@ -20,18 +20,21 @@ * isn't going to change. The right-hand side is the formatted string. * * Be sure to escape strings. + * The non-breaking blanks prevent ending an output line right before + * a number. Groff prevent line breaks at the same places. */ -LINE("v1", "Version 1 AT&T UNIX") -LINE("v2", "Version 2 AT&T UNIX") -LINE("v3", "Version 3 AT&T UNIX") -LINE("v4", "Version 4 AT&T UNIX") -LINE("v5", "Version 5 AT&T UNIX") -LINE("v6", "Version 6 AT&T UNIX") -LINE("v7", "Version 7 AT&T UNIX") -LINE("32v", "Version 32V AT&T UNIX") -LINE("V", "AT&T System V UNIX") -LINE("V.1", "AT&T System V.1 UNIX") -LINE("V.2", "AT&T System V.2 UNIX") -LINE("V.3", "AT&T System V.3 UNIX") -LINE("V.4", "AT&T System V.4 UNIX") +LINE("v1", "Version\\~1 AT&T UNIX") +LINE("v2", "Version\\~2 AT&T UNIX") +LINE("v3", "Version\\~3 AT&T UNIX") +LINE("v4", "Version\\~4 AT&T UNIX") +LINE("v5", "Version\\~5 AT&T UNIX") +LINE("v6", "Version\\~6 AT&T UNIX") +LINE("v7", "Version\\~7 AT&T UNIX") +LINE("32v", "Version\\~32V AT&T UNIX") +LINE("III", "AT&T System\\~III UNIX") +LINE("V", "AT&T System\\~V UNIX") +LINE("V.1", "AT&T System\\~V Release\\~1 UNIX") +LINE("V.2", "AT&T System\\~V Release\\~2 UNIX") +LINE("V.3", "AT&T System\\~V Release\\~3 UNIX") +LINE("V.4", "AT&T System\\~V Release\\~4 UNIX") diff --git a/external/bsd/mdocml/dist/catman.8 b/external/bsd/mdocml/dist/catman.8 new file mode 100644 index 000000000..780b74a15 --- /dev/null +++ b/external/bsd/mdocml/dist/catman.8 @@ -0,0 +1,111 @@ +.\" $Vendor-Id: catman.8,v 1.5 2011/12/25 19:35:44 kristaps Exp $ +.\" +.\" Copyright (c) 2011 Kristaps Dzonsons +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd December 25, 2011 +.Dt CATMAN 8 +.Os +.Sh NAME +.Nm catman +.Nd update a man.cgi manpage cache +.Sh SYNOPSIS +.Nm catman +.Op Fl fv +.Op Fl C Ar file +.Op Fl M Ar manpath +.Op Fl m Ar manpath +.Op Fl o Ar path +.Sh DESCRIPTION +The +.Nm +utility updates cached manpages for a jailed +.Xr man.cgi 7 . +.Pp +By default, +.Nm +searches for +.Xr mandocdb 8 +databases in the default paths stipulated by +.Xr man 1 +and updates the cache in +.Pa /var/www/cache/man.cgi . +.Pp +Its arguments are as follows: +.Bl -tag -width Ds +.It Fl f +Force an update to all files. +.It Fl v +Print each file being updated. +.It Fl C Ar file +Specify an alternative configuration +.Ar file +in +.Xr man.conf 5 +format. +.It Fl M Ar manpath +Use the colon-separated path instead of the default list of paths +searched for +.Xr mandocdb 8 +databases. +Invalid paths, or paths without manual databases, are ignored. +.It Fl m Ar manpath +Prepend the colon-separated paths to the list of paths searched +for +.Xr mandocdb 8 +databases. +Invalid paths, or paths without manual databases, are ignored. +.It Fl o Ar path +Update into the directory tree under +.Ar path . +.El +.Pp +Cache updates occur when a +.Xr mandocdb 8 +database is older than the cached copy unless +.Fl f +is specified, in which case files are always considered out of date. +Cached manual pages are only updated if older than the master copy. +.Sh ENVIRONMENT +.Bl -tag -width Ds +.It Ev MANPATH +Colon-separated paths modifying the default list of paths searched for +manual databases. +Invalid paths, or paths without manual databases, are ignored. +Overridden by +.Fl M . +If +.Ev MANPATH +begins with a +.Sq \&: , +it is appended to the default list; +else if it ends with +.Sq \&: , +it is prepended to the default list; else if it contains +.Sq \&:: , +the default list is inserted between the colons. +If none of these conditions are met, it overrides the default list. +.El +.Sh EXIT STATUS +.Ex -std +.Sh SEE ALSO +.Xr mandoc 1 , +.Xr man.cgi 7 , +.Xr mandocdb 8 +.Sh AUTHORS +The +.Nm +utility was written by +.An Kristaps Dzonsons , +.Mt kristaps@bsd.lv . diff --git a/external/bsd/mdocml/dist/catman.c b/external/bsd/mdocml/dist/catman.c new file mode 100644 index 000000000..88e36973b --- /dev/null +++ b/external/bsd/mdocml/dist/catman.c @@ -0,0 +1,511 @@ +/* $Vendor-Id: catman.c,v 1.10 2012/01/03 15:17:20 kristaps Exp $ */ +/* + * Copyright (c) 2011 Kristaps Dzonsons + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __linux__ +# include +#else +# include +#endif + +#include "manpath.h" +#include "mandocdb.h" + +#define xstrlcpy(_dst, _src, _sz) \ + do if (strlcpy((_dst), (_src), (_sz)) >= (_sz)) { \ + fprintf(stderr, "%s: Path too long", (_dst)); \ + exit(EXIT_FAILURE); \ + } while (/* CONSTCOND */0) + +#define xstrlcat(_dst, _src, _sz) \ + do if (strlcat((_dst), (_src), (_sz)) >= (_sz)) { \ + fprintf(stderr, "%s: Path too long", (_dst)); \ + exit(EXIT_FAILURE); \ + } while (/* CONSTCOND */0) + +static int indexhtml(char *, size_t, char *, size_t); +static int manup(const struct manpaths *, char *); +static int mkpath(char *, mode_t, mode_t); +static int treecpy(char *, char *); +static int update(char *, char *); +static void usage(void); + +static const char *progname; +static int verbose; +static int force; + +int +main(int argc, char *argv[]) +{ + int ch; + char *aux, *base, *conf_file; + struct manpaths dirs; + char buf[MAXPATHLEN]; + extern char *optarg; + extern int optind; + + progname = strrchr(argv[0], '/'); + if (progname == NULL) + progname = argv[0]; + else + ++progname; + + aux = base = conf_file = NULL; + xstrlcpy(buf, "/var/www/cache/man.cgi", MAXPATHLEN); + + while (-1 != (ch = getopt(argc, argv, "C:fm:M:o:v"))) + switch (ch) { + case ('C'): + conf_file = optarg; + break; + case ('f'): + force = 1; + break; + case ('m'): + aux = optarg; + break; + case ('M'): + base = optarg; + break; + case ('o'): + xstrlcpy(buf, optarg, MAXPATHLEN); + break; + case ('v'): + verbose++; + break; + default: + usage(); + return(EXIT_FAILURE); + } + + argc -= optind; + argv += optind; + + if (argc > 0) { + usage(); + return(EXIT_FAILURE); + } + + memset(&dirs, 0, sizeof(struct manpaths)); + manpath_parse(&dirs, conf_file, base, aux); + ch = manup(&dirs, buf); + manpath_free(&dirs); + return(ch ? EXIT_SUCCESS : EXIT_FAILURE); +} + +static void +usage(void) +{ + + fprintf(stderr, "usage: %s " + "[-fv] " + "[-C file] " + "[-o path] " + "[-m manpath] " + "[-M manpath]\n", + progname); +} + +/* + * If "src" file doesn't exist (errors out), return -1. Otherwise, + * return 1 if "src" is newer (which also happens "dst" doesn't exist) + * and 0 otherwise. + */ +static int +isnewer(const char *dst, const char *src) +{ + struct stat s1, s2; + + if (-1 == stat(src, &s1)) + return(-1); + if (force) + return(1); + + return(-1 == stat(dst, &s2) ? 1 : s1.st_mtime > s2.st_mtime); +} + +/* + * Copy the contents of one file into another. + * Returns 0 on failure, 1 on success. + */ +static int +filecpy(const char *dst, const char *src) +{ + char buf[BUFSIZ]; + int sfd, dfd, rc; + ssize_t rsz, wsz; + + sfd = dfd = -1; + rc = 0; + + if (-1 == (dfd = open(dst, O_CREAT|O_TRUNC|O_WRONLY, 0644))) { + perror(dst); + goto out; + } else if (-1 == (sfd = open(src, O_RDONLY, 0))) { + perror(src); + goto out; + } + + while ((rsz = read(sfd, buf, BUFSIZ)) > 0) + if (-1 == (wsz = write(dfd, buf, (size_t)rsz))) { + perror(dst); + goto out; + } else if (wsz < rsz) { + fprintf(stderr, "%s: Short write\n", dst); + goto out; + } + + if (rsz < 0) + perror(src); + else + rc = 1; +out: + if (-1 != sfd) + close(sfd); + if (-1 != dfd) + close(dfd); + + return(rc); +} + +/* + * Pass over the recno database and re-create HTML pages if they're + * found to be out of date. + * Returns -1 on fatal error, 1 on success. + */ +static int +indexhtml(char *src, size_t ssz, char *dst, size_t dsz) +{ + DB *idx; + DBT key, val; + int c, rc; + unsigned int fl; + const char *f; + char *d; + char fname[MAXPATHLEN]; + pid_t pid; + + pid = -1; + + xstrlcpy(fname, dst, MAXPATHLEN); + xstrlcat(fname, "/", MAXPATHLEN); + xstrlcat(fname, MANDOC_IDX, MAXPATHLEN); + + idx = dbopen(fname, O_RDONLY, 0, DB_RECNO, NULL); + if (NULL == idx) { + perror(fname); + return(-1); + } + + fl = R_FIRST; + while (0 == (c = (*idx->seq)(idx, &key, &val, fl))) { + fl = R_NEXT; + /* + * If the record is zero-length, then it's unassigned. + * Skip past these. + */ + if (0 == val.size) + continue; + + f = (const char *)val.data + 1; + if (NULL == memchr(f, '\0', val.size - 1)) + break; + + src[(int)ssz] = dst[(int)dsz] = '\0'; + + xstrlcat(dst, "/", MAXPATHLEN); + xstrlcat(dst, f, MAXPATHLEN); + + xstrlcat(src, "/", MAXPATHLEN); + xstrlcat(src, f, MAXPATHLEN); + + if (-1 == (rc = isnewer(dst, src))) { + fprintf(stderr, "%s: File missing\n", f); + break; + } else if (0 == rc) + continue; + + d = strrchr(dst, '/'); + assert(NULL != d); + *d = '\0'; + + if (-1 == mkpath(dst, 0755, 0755)) { + perror(dst); + break; + } + + *d = '/'; + + if ( ! filecpy(dst, src)) + break; + if (verbose) + printf("%s\n", dst); + } + + (*idx->close)(idx); + + if (c < 0) + perror(fname); + else if (0 == c) + fprintf(stderr, "%s: Corrupt index\n", fname); + + return(1 == c ? 1 : -1); +} + +/* + * Copy both recno and btree databases into the destination. + * Call in to begin recreating HTML files. + * Return -1 on fatal error and 1 if the update went well. + */ +static int +update(char *dst, char *src) +{ + size_t dsz, ssz; + + dsz = strlen(dst); + ssz = strlen(src); + + xstrlcat(src, "/", MAXPATHLEN); + xstrlcat(dst, "/", MAXPATHLEN); + + xstrlcat(src, MANDOC_DB, MAXPATHLEN); + xstrlcat(dst, MANDOC_DB, MAXPATHLEN); + + if ( ! filecpy(dst, src)) + return(-1); + if (verbose) + printf("%s\n", dst); + + dst[(int)dsz] = src[(int)ssz] = '\0'; + + xstrlcat(src, "/", MAXPATHLEN); + xstrlcat(dst, "/", MAXPATHLEN); + + xstrlcat(src, MANDOC_IDX, MAXPATHLEN); + xstrlcat(dst, MANDOC_IDX, MAXPATHLEN); + + if ( ! filecpy(dst, src)) + return(-1); + if (verbose) + printf("%s\n", dst); + + dst[(int)dsz] = src[(int)ssz] = '\0'; + + return(indexhtml(src, ssz, dst, dsz)); +} + +/* + * See if btree or recno databases in the destination are out of date + * with respect to a single manpath component. + * Return -1 on fatal error, 0 if the source is no longer valid (and + * shouldn't be listed), and 1 if the update went well. + */ +static int +treecpy(char *dst, char *src) +{ + size_t dsz, ssz; + int rc; + + dsz = strlen(dst); + ssz = strlen(src); + + xstrlcat(src, "/", MAXPATHLEN); + xstrlcat(dst, "/", MAXPATHLEN); + + xstrlcat(src, MANDOC_IDX, MAXPATHLEN); + xstrlcat(dst, MANDOC_IDX, MAXPATHLEN); + + if (-1 == (rc = isnewer(dst, src))) + return(0); + + dst[(int)dsz] = src[(int)ssz] = '\0'; + + if (1 == rc) + return(update(dst, src)); + + xstrlcat(src, "/", MAXPATHLEN); + xstrlcat(dst, "/", MAXPATHLEN); + + xstrlcat(src, MANDOC_DB, MAXPATHLEN); + xstrlcat(dst, MANDOC_DB, MAXPATHLEN); + + if (-1 == (rc = isnewer(dst, src))) + return(0); + else if (rc == 0) + return(1); + + dst[(int)dsz] = src[(int)ssz] = '\0'; + + return(update(dst, src)); +} + +/* + * Update the destination's file-tree with respect to changes in the + * source manpath components. + * "Change" is defined by an updated index or btree database. + * Returns 1 on success, 0 on failure. + */ +static int +manup(const struct manpaths *dirs, char *base) +{ + char dst[MAXPATHLEN], + src[MAXPATHLEN]; + const char *path; + int i, c; + size_t sz; + FILE *f; + + /* Create the path and file for the catman.conf file. */ + + sz = strlen(base); + xstrlcpy(dst, base, MAXPATHLEN); + xstrlcat(dst, "/etc", MAXPATHLEN); + if (-1 == mkpath(dst, 0755, 0755)) { + perror(dst); + return(0); + } + + xstrlcat(dst, "/catman.conf", MAXPATHLEN); + if (NULL == (f = fopen(dst, "w"))) { + perror(dst); + return(0); + } else if (verbose) + printf("%s\n", dst); + + for (i = 0; i < dirs->sz; i++) { + path = dirs->paths[i]; + dst[(int)sz] = '\0'; + xstrlcat(dst, path, MAXPATHLEN); + if (-1 == mkpath(dst, 0755, 0755)) { + perror(dst); + break; + } + + xstrlcpy(src, path, MAXPATHLEN); + if (-1 == (c = treecpy(dst, src))) + break; + else if (0 == c) + continue; + + /* + * We want to use a relative path here because manpath.h + * will realpath() when invoked with man.cgi, and we'll + * make sure to chdir() into the cache directory before. + * + * This allows the cache directory to be in an arbitrary + * place, working in both chroot() and non-chroot() + * "safe" modes. + */ + assert('/' == path[0]); + fprintf(f, "_whatdb %s/whatis.db\n", path + 1); + } + + fclose(f); + return(i == dirs->sz); +} + +/* + * Copyright (c) 1983, 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +static int +mkpath(char *path, mode_t mode, mode_t dir_mode) +{ + struct stat sb; + char *slash; + int done, exists; + + slash = path; + + for (;;) { + /* LINTED */ + slash += strspn(slash, "/"); + /* LINTED */ + slash += strcspn(slash, "/"); + + done = (*slash == '\0'); + *slash = '\0'; + + /* skip existing path components */ + exists = !stat(path, &sb); + if (!done && exists && S_ISDIR(sb.st_mode)) { + *slash = '/'; + continue; + } + + if (mkdir(path, done ? mode : dir_mode) == 0) { + if (mode > 0777 && chmod(path, mode) < 0) + return (-1); + } else { + if (!exists) { + /* Not there */ + return (-1); + } + if (!S_ISDIR(sb.st_mode)) { + /* Is there, but isn't a directory */ + errno = ENOTDIR; + return (-1); + } + } + + if (done) + break; + + *slash = '/'; + } + + return (0); +} diff --git a/external/bsd/mdocml/dist/cgi.c b/external/bsd/mdocml/dist/cgi.c new file mode 100644 index 000000000..48980dc41 --- /dev/null +++ b/external/bsd/mdocml/dist/cgi.c @@ -0,0 +1,1210 @@ +/* $Vendor-Id: cgi.c,v 1.39 2011/12/25 17:49:52 kristaps Exp $ */ +/* + * Copyright (c) 2011 Kristaps Dzonsons + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "apropos_db.h" +#include "mandoc.h" +#include "mdoc.h" +#include "man.h" +#include "main.h" +#include "manpath.h" +#include "mandocdb.h" + +#ifdef __linux__ +# include +#else +# include +#endif + +enum page { + PAGE_INDEX, + PAGE_SEARCH, + PAGE_SHOW, + PAGE__MAX +}; + +struct paths { + char *name; + char *path; +}; + +/* + * A query as passed to the search function. + */ +struct query { + const char *arch; /* architecture */ + const char *sec; /* manual section */ + const char *expr; /* unparsed expression string */ + int manroot; /* manroot index (or -1)*/ + int whatis; /* whether whatis mode */ + int legacy; /* whether legacy mode */ +}; + +struct req { + struct query q; + struct paths *p; + size_t psz; + enum page page; +}; + +static int atou(const char *, unsigned *); +static void catman(const struct req *, const char *); +static int cmp(const void *, const void *); +static void format(const struct req *, const char *); +static void html_print(const char *); +static void html_printquery(const struct req *); +static void html_putchar(char); +static int http_decode(char *); +static void http_parse(struct req *, char *); +static void http_print(const char *); +static void http_putchar(char); +static void http_printquery(const struct req *); +static int pathstop(DIR *); +static void pathgen(DIR *, char *, struct req *); +static void pg_index(const struct req *, char *); +static void pg_search(const struct req *, char *); +static void pg_show(const struct req *, char *); +static void resp_bad(void); +static void resp_baddb(void); +static void resp_error400(void); +static void resp_error404(const char *); +static void resp_begin_html(int, const char *); +static void resp_begin_http(int, const char *); +static void resp_end_html(void); +static void resp_index(const struct req *); +static void resp_search(struct res *, size_t, void *); +static void resp_searchform(const struct req *); + +static const char *progname; /* cgi script name */ +static const char *cache; /* cache directory */ +static const char *css; /* css directory */ +static const char *host; /* hostname */ + +static const char * const pages[PAGE__MAX] = { + "index", /* PAGE_INDEX */ + "search", /* PAGE_SEARCH */ + "show", /* PAGE_SHOW */ +}; + +/* + * This is just OpenBSD's strtol(3) suggestion. + * I use it instead of strtonum(3) for portability's sake. + */ +static int +atou(const char *buf, unsigned *v) +{ + char *ep; + long lval; + + errno = 0; + lval = strtol(buf, &ep, 10); + if (buf[0] == '\0' || *ep != '\0') + return(0); + if ((errno == ERANGE && (lval == LONG_MAX || + lval == LONG_MIN)) || + (lval > INT_MAX || lval < 0)) + return(0); + + *v = (unsigned int)lval; + return(1); +} + +/* + * Print a character, escaping HTML along the way. + * This will pass non-ASCII straight to output: be warned! + */ +static void +html_putchar(char c) +{ + + switch (c) { + case ('"'): + printf(""e;"); + break; + case ('&'): + printf("&"); + break; + case ('>'): + printf(">"); + break; + case ('<'): + printf("<"); + break; + default: + putchar((unsigned char)c); + break; + } +} +static void +http_printquery(const struct req *req) +{ + + printf("&expr="); + http_print(req->q.expr ? req->q.expr : ""); + printf("&sec="); + http_print(req->q.sec ? req->q.sec : ""); + printf("&arch="); + http_print(req->q.arch ? req->q.arch : ""); +} + + +static void +html_printquery(const struct req *req) +{ + + printf("&expr="); + html_print(req->q.expr ? req->q.expr : ""); + printf("&sec="); + html_print(req->q.sec ? req->q.sec : ""); + printf("&arch="); + html_print(req->q.arch ? req->q.arch : ""); +} + +static void +http_print(const char *p) +{ + + if (NULL == p) + return; + while ('\0' != *p) + http_putchar(*p++); +} + +/* + * Call through to html_putchar(). + * Accepts NULL strings. + */ +static void +html_print(const char *p) +{ + + if (NULL == p) + return; + while ('\0' != *p) + html_putchar(*p++); +} + +/* + * Parse out key-value pairs from an HTTP request variable. + * This can be either a cookie or a POST/GET string, although man.cgi + * uses only GET for simplicity. + */ +static void +http_parse(struct req *req, char *p) +{ + char *key, *val, *manroot; + int i, legacy; + + memset(&req->q, 0, sizeof(struct query)); + + req->q.whatis = 1; + legacy = -1; + manroot = NULL; + + while ('\0' != *p) { + key = p; + val = NULL; + + p += (int)strcspn(p, ";&"); + if ('\0' != *p) + *p++ = '\0'; + if (NULL != (val = strchr(key, '='))) + *val++ = '\0'; + + if ('\0' == *key || NULL == val || '\0' == *val) + continue; + + /* Just abort handling. */ + + if ( ! http_decode(key)) + break; + if (NULL != val && ! http_decode(val)) + break; + + if (0 == strcmp(key, "expr")) + req->q.expr = val; + else if (0 == strcmp(key, "query")) + req->q.expr = val; + else if (0 == strcmp(key, "sec")) + req->q.sec = val; + else if (0 == strcmp(key, "sektion")) + req->q.sec = val; + else if (0 == strcmp(key, "arch")) + req->q.arch = val; + else if (0 == strcmp(key, "manpath")) + manroot = val; + else if (0 == strcmp(key, "apropos")) + legacy = 0 == strcmp(val, "0"); + else if (0 == strcmp(key, "op")) + req->q.whatis = 0 == strcasecmp(val, "whatis"); + } + + /* Test for old man.cgi compatibility mode. */ + + if (legacy == 0) { + req->q.whatis = 0; + req->q.legacy = 1; + } else if (legacy > 0) { + req->q.legacy = 1; + req->q.whatis = 1; + } + + /* + * Section "0" means no section when in legacy mode. + * For some man.cgi scripts, "default" arch is none. + */ + + if (req->q.legacy && NULL != req->q.sec) + if (0 == strcmp(req->q.sec, "0")) + req->q.sec = NULL; + if (req->q.legacy && NULL != req->q.arch) + if (0 == strcmp(req->q.arch, "default")) + req->q.arch = NULL; + + /* Default to first manroot. */ + + if (NULL != manroot) { + for (i = 0; i < (int)req->psz; i++) + if (0 == strcmp(req->p[i].name, manroot)) + break; + req->q.manroot = i < (int)req->psz ? i : -1; + } +} + +static void +http_putchar(char c) +{ + + if (isalnum((unsigned char)c)) { + putchar((unsigned char)c); + return; + } else if (' ' == c) { + putchar('+'); + return; + } + printf("%%%.2x", c); +} + +/* + * HTTP-decode a string. The standard explanation is that this turns + * "%4e+foo" into "n foo" in the regular way. This is done in-place + * over the allocated string. + */ +static int +http_decode(char *p) +{ + char hex[3]; + int c; + + hex[2] = '\0'; + + for ( ; '\0' != *p; p++) { + if ('%' == *p) { + if ('\0' == (hex[0] = *(p + 1))) + return(0); + if ('\0' == (hex[1] = *(p + 2))) + return(0); + if (1 != sscanf(hex, "%x", &c)) + return(0); + if ('\0' == c) + return(0); + + *p = (char)c; + memmove(p + 1, p + 3, strlen(p + 3) + 1); + } else + *p = '+' == *p ? ' ' : *p; + } + + *p = '\0'; + return(1); +} + +static void +resp_begin_http(int code, const char *msg) +{ + + if (200 != code) + printf("Status: %d %s\n", code, msg); + + puts("Content-Type: text/html; charset=utf-8\n" + "Cache-Control: no-cache\n" + "Pragma: no-cache\n" + ""); + + fflush(stdout); +} + +static void +resp_begin_html(int code, const char *msg) +{ + + resp_begin_http(code, msg); + + printf("\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "System Manpage Reference\n" + "\n" + "\n" + "\n", css, css); +} + +static void +resp_end_html(void) +{ + + puts("\n" + ""); +} + +static void +resp_searchform(const struct req *req) +{ + int i; + + puts(""); + printf("
\n" + "
\n" + "
\n" + "Search Parameters\n" + " or \n" + " for manuals satisfying \n" + "q.expr ? req->q.expr : ""); + printf("\">, section " + "q.sec ? req->q.sec : ""); + printf("\">, arch " + "q.arch ? req->q.arch : ""); + printf("\">"); + if (req->psz > 1) { + puts(", "); + } + puts(".\n" + "\n" + "
\n" + "
\n" + "
"); + puts(""); +} + +static void +resp_index(const struct req *req) +{ + + resp_begin_html(200, NULL); + resp_searchform(req); + resp_end_html(); +} + +static void +resp_error400(void) +{ + + resp_begin_html(400, "Query Malformed"); + printf("

Malformed Query

\n" + "

\n" + "The query your entered was malformed.\n" + "Try again from the\n" + "main page.\n" + "

", progname); + resp_end_html(); +} + +static void +resp_error404(const char *page) +{ + + resp_begin_html(404, "Not Found"); + puts("

Page Not Found

\n" + "

\n" + "The page you're looking for, "); + printf(""); + html_print(page); + printf(",\n" + "could not be found.\n" + "Try searching from the\n" + "main page.\n" + "

", progname); + resp_end_html(); +} + +static void +resp_bad(void) +{ + resp_begin_html(500, "Internal Server Error"); + puts("

Generic badness happened.

"); + resp_end_html(); +} + +static void +resp_baddb(void) +{ + + resp_begin_html(500, "Internal Server Error"); + puts("

Your database is broken.

"); + resp_end_html(); +} + +static void +resp_search(struct res *r, size_t sz, void *arg) +{ + int i; + const struct req *req; + + req = (const struct req *)arg; + + if (sz > 0) + assert(req->q.manroot >= 0); + + if (1 == sz) { + /* + * If we have just one result, then jump there now + * without any delay. + */ + puts("Status: 303 See Other"); + printf("Location: http://%s%s/show/%d/%u/%u.html?", + host, progname, req->q.manroot, + r[0].volume, r[0].rec); + http_printquery(req); + puts("\n" + "Content-Type: text/html; charset=utf-8\n"); + return; + } + + qsort(r, sz, sizeof(struct res), cmp); + + resp_begin_html(200, NULL); + resp_searchform(req); + + puts("
"); + + if (0 == sz) { + printf("

\n" + "No %s results found.\n", + req->q.whatis ? "whatis" : "apropos"); + if (req->q.whatis) { + printf("(Try " + "apropos?)"); + } + puts("

"); + puts("
"); + resp_end_html(); + return; + } + + puts(""); + + for (i = 0; i < (int)sz; i++) { + printf("\n" + "\n" + "\n" + ""); + } + + puts("
\n" + "q.manroot, + r[i].volume, r[i].rec); + html_printquery(req); + printf("\">"); + html_print(r[i].title); + putchar('('); + html_print(r[i].cat); + if (r[i].arch && '\0' != *r[i].arch) { + putchar('/'); + html_print(r[i].arch); + } + printf(")\n" + ""); + html_print(r[i].desc); + puts("
\n" + ""); + resp_end_html(); +} + +/* ARGSUSED */ +static void +pg_index(const struct req *req, char *path) +{ + + resp_index(req); +} + +static void +catman(const struct req *req, const char *file) +{ + FILE *f; + size_t len; + int i; + char *p; + int italic, bold; + + if (NULL == (f = fopen(file, "r"))) { + resp_baddb(); + return; + } + + resp_begin_html(200, NULL); + resp_searchform(req); + puts("
\n" + "
");
+
+	while (NULL != (p = fgetln(f, &len))) {
+		bold = italic = 0;
+		for (i = 0; i < (int)len - 1; i++) {
+			/* 
+			 * This means that the catpage is out of state.
+			 * Ignore it and keep going (although the
+			 * catpage is bogus).
+			 */
+
+			if ('\b' == p[i] || '\n' == p[i])
+				continue;
+
+			/*
+			 * Print a regular character.
+			 * Close out any bold/italic scopes.
+			 * If we're in back-space mode, make sure we'll
+			 * have something to enter when we backspace.
+			 */
+
+			if ('\b' != p[i + 1]) {
+				if (italic)
+					printf("");
+				if (bold)
+					printf("");
+				italic = bold = 0;
+				html_putchar(p[i]);
+				continue;
+			} else if (i + 2 >= (int)len)
+				continue;
+
+			/* Italic mode. */
+
+			if ('_' == p[i]) {
+				if (bold)
+					printf("");
+				if ( ! italic)
+					printf("");
+				bold = 0;
+				italic = 1;
+				i += 2;
+				html_putchar(p[i]);
+				continue;
+			}
+
+			/* 
+			 * Handle funny behaviour troff-isms.
+			 * These grok'd from the original man2html.c.
+			 */
+
+			if (('+' == p[i] && 'o' == p[i + 2]) ||
+					('o' == p[i] && '+' == p[i + 2]) ||
+					('|' == p[i] && '=' == p[i + 2]) ||
+					('=' == p[i] && '|' == p[i + 2]) ||
+					('*' == p[i] && '=' == p[i + 2]) ||
+					('=' == p[i] && '*' == p[i + 2]) ||
+					('*' == p[i] && '|' == p[i + 2]) ||
+					('|' == p[i] && '*' == p[i + 2]))  {
+				if (italic)
+					printf("");
+				if (bold)
+					printf("");
+				italic = bold = 0;
+				putchar('*');
+				i += 2;
+				continue;
+			} else if (('|' == p[i] && '-' == p[i + 2]) ||
+					('-' == p[i] && '|' == p[i + 1]) ||
+					('+' == p[i] && '-' == p[i + 1]) ||
+					('-' == p[i] && '+' == p[i + 1]) ||
+					('+' == p[i] && '|' == p[i + 1]) ||
+					('|' == p[i] && '+' == p[i + 1]))  {
+				if (italic)
+					printf("");
+				if (bold)
+					printf("");
+				italic = bold = 0;
+				putchar('+');
+				i += 2;
+				continue;
+			}
+
+			/* Bold mode. */
+			
+			if (italic)
+				printf("");
+			if ( ! bold)
+				printf("");
+			bold = 1;
+			italic = 0;
+			i += 2;
+			html_putchar(p[i]);
+		}
+
+		/* 
+		 * Clean up the last character.
+		 * We can get to a newline; don't print that. 
+		 */
+
+		if (italic)
+			printf("");
+		if (bold)
+			printf("");
+
+		if (i == (int)len - 1 && '\n' != p[i])
+			html_putchar(p[i]);
+
+		putchar('\n');
+	}
+
+	puts("
\n" + "
\n" + "\n" + ""); + + fclose(f); +} + +static void +format(const struct req *req, const char *file) +{ + struct mparse *mp; + int fd; + struct mdoc *mdoc; + struct man *man; + void *vp; + enum mandoclevel rc; + char opts[MAXPATHLEN + 128]; + + if (-1 == (fd = open(file, O_RDONLY, 0))) { + resp_baddb(); + return; + } + + mp = mparse_alloc(MPARSE_AUTO, MANDOCLEVEL_FATAL, NULL, NULL); + rc = mparse_readfd(mp, fd, file); + close(fd); + + if (rc >= MANDOCLEVEL_FATAL) { + resp_baddb(); + return; + } + + snprintf(opts, sizeof(opts), "fragment," + "man=%s/search.html?sec=%%S&expr=%%N," + /*"includes=/cgi-bin/man.cgi/usr/include/%%I"*/, + progname); + + mparse_result(mp, &mdoc, &man); + if (NULL == man && NULL == mdoc) { + resp_baddb(); + mparse_free(mp); + return; + } + + resp_begin_html(200, NULL); + resp_searchform(req); + + vp = html_alloc(opts); + + if (NULL != mdoc) + html_mdoc(vp, mdoc); + else + html_man(vp, man); + + puts("\n" + ""); + + html_free(vp); + mparse_free(mp); +} + +static void +pg_show(const struct req *req, char *path) +{ + struct manpaths ps; + size_t sz; + char *sub; + char file[MAXPATHLEN]; + const char *cp; + int rc, catm; + unsigned int vol, rec, mr; + DB *idx; + DBT key, val; + + idx = NULL; + + /* Parse out mroot, volume, and record from the path. */ + + if (NULL == path || NULL == (sub = strchr(path, '/'))) { + resp_error400(); + return; + } + *sub++ = '\0'; + if ( ! atou(path, &mr)) { + resp_error400(); + return; + } + path = sub; + if (NULL == (sub = strchr(path, '/'))) { + resp_error400(); + return; + } + *sub++ = '\0'; + if ( ! atou(path, &vol) || ! atou(sub, &rec)) { + resp_error400(); + return; + } else if (mr >= (unsigned int)req->psz) { + resp_error400(); + return; + } + + /* + * Begin by chdir()ing into the manroot. + * This way we can pick up the database files, which are + * relative to the manpath root. + */ + + if (-1 == chdir(req->p[(int)mr].path)) { + perror(req->p[(int)mr].path); + resp_baddb(); + return; + } + + memset(&ps, 0, sizeof(struct manpaths)); + manpath_manconf(&ps, "etc/catman.conf"); + + if (vol >= (unsigned int)ps.sz) { + resp_error400(); + goto out; + } + + sz = strlcpy(file, ps.paths[vol], MAXPATHLEN); + assert(sz < MAXPATHLEN); + strlcat(file, "/", MAXPATHLEN); + strlcat(file, MANDOC_IDX, MAXPATHLEN); + + /* Open the index recno(3) database. */ + + idx = dbopen(file, O_RDONLY, 0, DB_RECNO, NULL); + if (NULL == idx) { + perror(file); + resp_baddb(); + goto out; + } + + key.data = &rec; + key.size = 4; + + if (0 != (rc = (*idx->get)(idx, &key, &val, 0))) { + rc < 0 ? resp_baddb() : resp_error400(); + goto out; + } else if (0 == val.size) { + resp_baddb(); + goto out; + } + + cp = (char *)val.data; + catm = 'c' == *cp++; + + if (NULL == memchr(cp, '\0', val.size - 1)) + resp_baddb(); + else { + file[(int)sz] = '\0'; + strlcat(file, "/", MAXPATHLEN); + strlcat(file, cp, MAXPATHLEN); + if (catm) + catman(req, file); + else + format(req, file); + } +out: + if (idx) + (*idx->close)(idx); + manpath_free(&ps); +} + +static void +pg_search(const struct req *req, char *path) +{ + size_t tt; + struct manpaths ps; + int i, sz, rc; + const char *ep, *start; + char **cp; + struct opts opt; + struct expr *expr; + + if (req->q.manroot < 0 || 0 == req->psz) { + resp_search(NULL, 0, (void *)req); + return; + } + + memset(&opt, 0, sizeof(struct opts)); + + ep = req->q.expr; + opt.arch = req->q.arch; + opt.cat = req->q.sec; + rc = -1; + sz = 0; + cp = NULL; + + /* + * Begin by chdir()ing into the root of the manpath. + * This way we can pick up the database files, which are + * relative to the manpath root. + */ + + assert(req->q.manroot < (int)req->psz); + if (-1 == (chdir(req->p[req->q.manroot].path))) { + perror(req->p[req->q.manroot].path); + resp_search(NULL, 0, (void *)req); + return; + } + + memset(&ps, 0, sizeof(struct manpaths)); + manpath_manconf(&ps, "etc/catman.conf"); + + /* + * Poor man's tokenisation: just break apart by spaces. + * Yes, this is half-ass. But it works for now. + */ + + while (ep && isspace((unsigned char)*ep)) + ep++; + + while (ep && '\0' != *ep) { + cp = mandoc_realloc(cp, (sz + 1) * sizeof(char *)); + start = ep; + while ('\0' != *ep && ! isspace((unsigned char)*ep)) + ep++; + cp[sz] = mandoc_malloc((ep - start) + 1); + memcpy(cp[sz], start, ep - start); + cp[sz++][ep - start] = '\0'; + while (isspace((unsigned char)*ep)) + ep++; + } + + /* + * Pump down into apropos backend. + * The resp_search() function is called with the results. + */ + + expr = req->q.whatis ? + termcomp(sz, cp, &tt) : exprcomp(sz, cp, &tt); + + if (NULL != expr) + rc = apropos_search + (ps.sz, ps.paths, &opt, + expr, tt, (void *)req, resp_search); + + /* ...unless errors occured. */ + + if (0 == rc) + resp_baddb(); + else if (-1 == rc) + resp_search(NULL, 0, (void *)req); + + for (i = 0; i < sz; i++) + free(cp[i]); + + free(cp); + exprfree(expr); + manpath_free(&ps); +} + +int +main(void) +{ + int i; + char buf[MAXPATHLEN]; + DIR *cwd; + struct req req; + char *p, *path, *subpath; + + /* Scan our run-time environment. */ + + if (NULL == (cache = getenv("CACHE_DIR"))) + cache = "/cache/man.cgi"; + + if (NULL == (progname = getenv("SCRIPT_NAME"))) + progname = ""; + + if (NULL == (css = getenv("CSS_DIR"))) + css = ""; + + if (NULL == (host = getenv("HTTP_HOST"))) + host = "localhost"; + + /* + * First we change directory into the cache directory so that + * subsequent scanning for manpath directories is rooted + * relative to the same position. + */ + + if (-1 == chdir(cache)) { + perror(cache); + resp_bad(); + return(EXIT_FAILURE); + } else if (NULL == (cwd = opendir(cache))) { + perror(cache); + resp_bad(); + return(EXIT_FAILURE); + } + + memset(&req, 0, sizeof(struct req)); + + strlcpy(buf, ".", MAXPATHLEN); + pathgen(cwd, buf, &req); + closedir(cwd); + + /* Next parse out the query string. */ + + if (NULL != (p = getenv("QUERY_STRING"))) + http_parse(&req, p); + + /* + * Now juggle paths to extract information. + * We want to extract our filetype (the file suffix), the + * initial path component, then the trailing component(s). + * Start with leading subpath component. + */ + + subpath = path = NULL; + req.page = PAGE__MAX; + + if (NULL == (path = getenv("PATH_INFO")) || '\0' == *path) + req.page = PAGE_INDEX; + + if (NULL != path && '/' == *path && '\0' == *++path) + req.page = PAGE_INDEX; + + /* Strip file suffix. */ + + if (NULL != path && NULL != (p = strrchr(path, '.'))) + if (NULL != p && NULL == strchr(p, '/')) + *p++ = '\0'; + + /* Resolve subpath component. */ + + if (NULL != path && NULL != (subpath = strchr(path, '/'))) + *subpath++ = '\0'; + + /* Map path into one we recognise. */ + + if (NULL != path && '\0' != *path) + for (i = 0; i < (int)PAGE__MAX; i++) + if (0 == strcmp(pages[i], path)) { + req.page = (enum page)i; + break; + } + + /* Route pages. */ + + switch (req.page) { + case (PAGE_INDEX): + pg_index(&req, subpath); + break; + case (PAGE_SEARCH): + pg_search(&req, subpath); + break; + case (PAGE_SHOW): + pg_show(&req, subpath); + break; + default: + resp_error404(path); + break; + } + + for (i = 0; i < (int)req.psz; i++) { + free(req.p[i].path); + free(req.p[i].name); + } + + free(req.p); + return(EXIT_SUCCESS); +} + +static int +cmp(const void *p1, const void *p2) +{ + + return(strcasecmp(((const struct res *)p1)->title, + ((const struct res *)p2)->title)); +} + +/* + * Check to see if an "etc" path consists of a catman.conf file. If it + * does, that means that the path contains a tree created by catman(8) + * and should be used for indexing. + */ +static int +pathstop(DIR *dir) +{ + struct dirent *d; + + while (NULL != (d = readdir(dir))) + if (DT_REG == d->d_type) + if (0 == strcmp(d->d_name, "catman.conf")) + return(1); + + return(0); +} + +/* + * Scan for indexable paths. + * This adds all paths with "etc/catman.conf" to the buffer. + */ +static void +pathgen(DIR *dir, char *path, struct req *req) +{ + struct dirent *d; + char *cp; + DIR *cd; + int rc; + size_t sz, ssz; + + sz = strlcat(path, "/", MAXPATHLEN); + if (sz >= MAXPATHLEN) { + fprintf(stderr, "%s: Path too long", path); + return; + } + + /* + * First, scan for the "etc" directory. + * If it's found, then see if it should cause us to stop. This + * happens when a catman.conf is found in the directory. + */ + + rc = 0; + while (0 == rc && NULL != (d = readdir(dir))) { + if (DT_DIR != d->d_type || strcmp(d->d_name, "etc")) + continue; + + path[(int)sz] = '\0'; + ssz = strlcat(path, d->d_name, MAXPATHLEN); + + if (ssz >= MAXPATHLEN) { + fprintf(stderr, "%s: Path too long", path); + return; + } else if (NULL == (cd = opendir(path))) { + perror(path); + return; + } + + rc = pathstop(cd); + closedir(cd); + } + + if (rc > 0) { + /* This also strips the trailing slash. */ + path[(int)--sz] = '\0'; + req->p = mandoc_realloc + (req->p, + (req->psz + 1) * sizeof(struct paths)); + /* + * Strip out the leading "./" unless we're just a ".", + * in which case use an empty string as our name. + */ + req->p[(int)req->psz].path = mandoc_strdup(path); + req->p[(int)req->psz].name = + cp = mandoc_strdup(path + (1 == sz ? 1 : 2)); + req->psz++; + /* + * The name is just the path with all the slashes taken + * out of it. Simple but effective. + */ + for ( ; '\0' != *cp; cp++) + if ('/' == *cp) + *cp = ' '; + return; + } + + /* + * If no etc/catman.conf was found, recursively enter child + * directory and continue scanning. + */ + + rewinddir(dir); + while (NULL != (d = readdir(dir))) { + if (DT_DIR != d->d_type || '.' == d->d_name[0]) + continue; + + path[(int)sz] = '\0'; + ssz = strlcat(path, d->d_name, MAXPATHLEN); + + if (ssz >= MAXPATHLEN) { + fprintf(stderr, "%s: Path too long", path); + return; + } else if (NULL == (cd = opendir(path))) { + perror(path); + return; + } + + pathgen(cd, path, req); + closedir(cd); + } +} diff --git a/external/bsd/mdocml/dist/chars.c b/external/bsd/mdocml/dist/chars.c index c22142b8e..ff105966b 100644 --- a/external/bsd/mdocml/dist/chars.c +++ b/external/bsd/mdocml/dist/chars.c @@ -1,6 +1,7 @@ -/* $Vendor-Id: chars.c,v 1.31 2011/01/02 10:10:57 kristaps Exp $ */ +/* $Vendor-Id: chars.c,v 1.52 2011/11/08 00:15:23 kristaps Exp $ */ /* - * Copyright (c) 2009, 2010 Kristaps Dzonsons + * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons + * Copyright (c) 2011 Ingo Schwarze * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -19,12 +20,12 @@ #endif #include -#include +#include #include #include #include "mandoc.h" -#include "chars.h" +#include "libmandoc.h" #define PRINT_HI 126 #define PRINT_LO 32 @@ -34,52 +35,37 @@ struct ln { const char *code; const char *ascii; int unicode; - int type; -#define CHARS_CHAR (1 << 0) -#define CHARS_STRING (1 << 1) -#define CHARS_BOTH (CHARS_CHAR | CHARS_STRING) }; -#define LINES_MAX 351 +#define LINES_MAX 328 #define CHAR(in, ch, code) \ - { NULL, (in), (ch), (code), CHARS_CHAR }, -#define STRING(in, ch, code) \ - { NULL, (in), (ch), (code), CHARS_STRING }, -#define BOTH(in, ch, code) \ - { NULL, (in), (ch), (code), CHARS_BOTH }, + { NULL, (in), (ch), (code) }, #define CHAR_TBL_START static struct ln lines[LINES_MAX] = { #define CHAR_TBL_END }; #include "chars.in" -struct ctab { - enum chars type; +struct mchars { struct ln **htab; }; -static inline int match(const struct ln *, - const char *, size_t, int); -static const struct ln *find(struct ctab *, const char *, size_t, int); - +static const struct ln *find(const struct mchars *, + const char *, size_t); void -chars_free(void *arg) +mchars_free(struct mchars *arg) { - struct ctab *tab; - tab = (struct ctab *)arg; - - free(tab->htab); - free(tab); + free(arg->htab); + free(arg); } - -void * -chars_init(enum chars type) +struct mchars * +mchars_alloc(void) { - struct ctab *tab; + struct mchars *tab; struct ln **htab; struct ln *pp; int i, hash; @@ -87,21 +73,11 @@ chars_init(enum chars type) /* * Constructs a very basic chaining hashtable. The hash routine * is simply the integral value of the first character. - * Subsequent entries are chained in the order they're processed - * (they're in-line re-ordered during lookup). + * Subsequent entries are chained in the order they're processed. */ - tab = malloc(sizeof(struct ctab)); - if (NULL == tab) { - perror(NULL); - exit((int)MANDOCLEVEL_SYSERR); - } - - htab = calloc(PRINT_HI - PRINT_LO + 1, sizeof(struct ln **)); - if (NULL == htab) { - perror(NULL); - exit((int)MANDOCLEVEL_SYSERR); - } + tab = mandoc_malloc(sizeof(struct mchars)); + htab = mandoc_calloc(PRINT_HI - PRINT_LO + 1, sizeof(struct ln **)); for (i = 0; i < LINES_MAX; i++) { hash = (int)lines[i].code[0] - PRINT_LO; @@ -117,127 +93,75 @@ chars_init(enum chars type) } tab->htab = htab; - tab->type = type; return(tab); } - -/* - * Special character to Unicode codepoint. - */ int -chars_spec2cp(void *arg, const char *p, size_t sz) +mchars_spec2cp(const struct mchars *arg, const char *p, size_t sz) { const struct ln *ln; - ln = find((struct ctab *)arg, p, sz, CHARS_CHAR); + ln = find(arg, p, sz); if (NULL == ln) return(-1); return(ln->unicode); } +char +mchars_num2char(const char *p, size_t sz) +{ + int i; + + if ((i = mandoc_strntoi(p, sz, 10)) < 0) + return('\0'); + return(i > 0 && i < 256 && isprint(i) ? + /* LINTED */ i : '\0'); +} -/* - * Reserved word to Unicode codepoint. - */ int -chars_res2cp(void *arg, const char *p, size_t sz) +mchars_num2uc(const char *p, size_t sz) { - const struct ln *ln; + int i; - ln = find((struct ctab *)arg, p, sz, CHARS_STRING); - if (NULL == ln) - return(-1); - return(ln->unicode); + if ((i = mandoc_strntoi(p, sz, 16)) < 0) + return('\0'); + /* FIXME: make sure we're not in a bogus range. */ + return(i > 0x80 && i <= 0x10FFFF ? i : '\0'); } - -/* - * Special character to string array. - */ const char * -chars_spec2str(void *arg, const char *p, size_t sz, size_t *rsz) +mchars_spec2str(const struct mchars *arg, + const char *p, size_t sz, size_t *rsz) { const struct ln *ln; - ln = find((struct ctab *)arg, p, sz, CHARS_CHAR); - if (NULL == ln) + ln = find(arg, p, sz); + if (NULL == ln) { + *rsz = 1; return(NULL); + } *rsz = strlen(ln->ascii); return(ln->ascii); } - -/* - * Reserved word to string array. - */ -const char * -chars_res2str(void *arg, const char *p, size_t sz, size_t *rsz) -{ - const struct ln *ln; - - ln = find((struct ctab *)arg, p, sz, CHARS_STRING); - if (NULL == ln) - return(NULL); - - *rsz = strlen(ln->ascii); - return(ln->ascii); -} - - static const struct ln * -find(struct ctab *tab, const char *p, size_t sz, int type) +find(const struct mchars *tab, const char *p, size_t sz) { - struct ln *pp, *prev; - struct ln **htab; + const struct ln *pp; int hash; assert(p); - if (0 == sz) - return(NULL); - if (p[0] < PRINT_LO || p[0] > PRINT_HI) + if (0 == sz || p[0] < PRINT_LO || p[0] > PRINT_HI) return(NULL); - /* - * Lookup the symbol in the symbol hash. See ascii2htab for the - * hashtable specs. This dynamically re-orders the hash chain - * to optimise for repeat hits. - */ - hash = (int)p[0] - PRINT_LO; - htab = tab->htab; - if (NULL == (pp = htab[hash])) - return(NULL); - - for (prev = NULL; pp; pp = pp->next) { - if ( ! match(pp, p, sz, type)) { - prev = pp; - continue; - } - - if (prev) { - prev->next = pp->next; - pp->next = htab[hash]; - htab[hash] = pp; - } - - return(pp); - } + for (pp = tab->htab[hash]; pp; pp = pp->next) + if (0 == strncmp(pp->code, p, sz) && + '\0' == pp->code[(int)sz]) + return(pp); return(NULL); } - - -static inline int -match(const struct ln *ln, const char *p, size_t sz, int type) -{ - - if ( ! (ln->type & type)) - return(0); - if (strncmp(ln->code, p, sz)) - return(0); - return('\0' == ln->code[(int)sz]); -} diff --git a/external/bsd/mdocml/dist/chars.h b/external/bsd/mdocml/dist/chars.h deleted file mode 100644 index ef67d21a2..000000000 --- a/external/bsd/mdocml/dist/chars.h +++ /dev/null @@ -1,36 +0,0 @@ -/* $Vendor-Id: chars.h,v 1.6 2010/07/31 23:52:58 schwarze Exp $ */ -/* - * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -#ifndef CHARS_H -#define CHARS_H - -__BEGIN_DECLS - -enum chars { - CHARS_ASCII, - CHARS_HTML -}; - -void *chars_init(enum chars); -const char *chars_spec2str(void *, const char *, size_t, size_t *); -int chars_spec2cp(void *, const char *, size_t); -const char *chars_res2str(void *, const char *, size_t, size_t *); -int chars_res2cp(void *, const char *, size_t); -void chars_free(void *); - -__END_DECLS - -#endif /*!CHARS_H*/ diff --git a/external/bsd/mdocml/dist/chars.in b/external/bsd/mdocml/dist/chars.in index 668f47f8e..53dd0b4b0 100644 --- a/external/bsd/mdocml/dist/chars.in +++ b/external/bsd/mdocml/dist/chars.in @@ -1,6 +1,6 @@ -/* $Vendor-Id: chars.in,v 1.35 2010/09/15 13:10:30 kristaps Exp $ */ +/* $Vendor-Id: chars.in,v 1.42 2011/10/02 10:02:26 kristaps Exp $ */ /* - * Copyright (c) 2009, 2010 Kristaps Dzonsons + * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -16,15 +16,12 @@ */ /* - * The ASCII translation tables. STRING corresponds to predefined - * strings (cf. mdoc_samples.7 and tmac/mdoc/doc-nroff). CHAR - * corresponds to special characters (cf. groff_char.7). BOTH contains - * sequences that are equivalent in both STRING and CHAR. + * The ASCII translation tables. * - * Either way, the left-hand side corresponds to the input sequence (\x, - * \(xx, \*(xx and so on) whose length is listed second element. The - * right-hand side is what's produced by the front-end, with the fourth - * element being its length. + * The left-hand side corresponds to the input sequence (\x, \(xx, \*(xx + * and so on) whose length is listed second element. The right-hand + * side is what's produced by the front-end, with the fourth element + * being its length. * * XXX - C-escape strings! * XXX - update LINES_MAX if adding more! @@ -51,10 +48,10 @@ CHAR("a\"", "\"", 779) CHAR("a-", "-", 175) CHAR("a.", ".", 729) CHAR("a^", "^", 770) -BOTH("\'", "\'", 769) -BOTH("aa", "\'", 769) -BOTH("ga", "`", 768) -BOTH("`", "`", 768) +CHAR("\'", "\'", 769) +CHAR("aa", "\'", 769) +CHAR("ga", "`", 768) +CHAR("`", "`", 768) CHAR("ab", "`", 774) CHAR("ac", ",", 807) CHAR("ad", "\"", 776) @@ -68,8 +65,8 @@ CHAR("ti", "~", 126) /* Quotes. */ CHAR("Bq", ",,", 8222) CHAR("bq", ",", 8218) -BOTH("lq", "``", 8220) -BOTH("rq", "\'\'", 8221) +CHAR("lq", "``", 8220) +CHAR("rq", "\'\'", 8221) CHAR("oq", "`", 8216) CHAR("cq", "\'", 8217) CHAR("aq", "\'", 39) @@ -187,7 +184,7 @@ CHAR(":U", "U", 220) CHAR(":a", "a", 228) CHAR(":e", "e", 235) CHAR(":i", "i", 239) -CHAR(":o", "o", 245) +CHAR(":o", "o", 246) CHAR(":u", "u", 252) CHAR(":y", "y", 255) CHAR("\'A", "A", 193) @@ -232,8 +229,8 @@ CHAR("<-", "<-", 8592) CHAR("->", "->", 8594) CHAR("<>", "<>", 8596) CHAR("da", "v", 8595) -BOTH("ua", "^", 8593) -BOTH("va", "^v", 8597) +CHAR("ua", "^", 8593) +CHAR("va", "^v", 8597) CHAR("lA", "<=", 8656) CHAR("rA", "=>", 8658) CHAR("hA", "<=>", 8660) @@ -270,8 +267,8 @@ CHAR("di", "-:-", 247) CHAR("tdi", "-:-", 247) CHAR("f/", "/", 8260) CHAR("**", "*", 8727) -BOTH("<=", "<=", 8804) -BOTH(">=", ">=", 8805) +CHAR("<=", "<=", 8804) +CHAR(">=", ">=", 8805) CHAR("<<", "<<", 8810) CHAR(">>", ">>", 8811) CHAR("eq", "=", 61) @@ -315,6 +312,9 @@ CHAR("Im", "I", 8465) CHAR("Re", "R", 8476) CHAR("pd", "a", 8706) CHAR("-h", "/h", 8463) +CHAR("12", "1/2", 189) +CHAR("14", "1/4", 188) +CHAR("34", "3/4", 190) /* Ligatures. */ CHAR("ff", "ff", 64256) @@ -348,34 +348,6 @@ CHAR("Po", "L", 163) CHAR("Cs", "x", 164) CHAR("Fn", "f", 402) -/* Old style. */ -STRING("Am", "&", 38) -STRING("Ba", "|", 124) -STRING("Ge", ">=", 8805) -STRING("Gt", ">", 62) -STRING("If", "infinity", 0) -STRING("Le", "<=", 8804) -STRING("Lq", "``", 8220) -STRING("Lt", "<", 60) -STRING("Na", "NaN", 0) -STRING("Ne", "!=", 8800) -STRING("Pi", "pi", 960) -STRING("Pm", "+-", 177) -STRING("Rq", "\'\'", 8221) -STRING("left-bracket", "[", 91) -STRING("left-parenthesis", "(", 40) -STRING("left-singlequote", "`", 8216) -STRING("lp", "(", 40) -STRING("q", "\"", 34) -STRING("quote-left", "`", 8216) -STRING("quote-right", "\'", 8217) -STRING("R", "(R)", 174) -STRING("right-bracket", "]", 93) -STRING("right-parenthesis", ")", 41) -STRING("right-singlequote", "\'", 8217) -STRING("rp", ")", 41) -STRING("Tm", "(Tm)", 8482) - /* Lines. */ CHAR("ba", "|", 124) CHAR("br", "|", 9474) diff --git a/external/bsd/mdocml/dist/compat_fgetln.c b/external/bsd/mdocml/dist/compat_fgetln.c new file mode 100644 index 000000000..8036c8810 --- /dev/null +++ b/external/bsd/mdocml/dist/compat_fgetln.c @@ -0,0 +1,93 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_FGETLN + +int dummy; + +#else + +/* $NetBSD: compat_fgetln.c,v 1.2 2012/01/30 17:03:01 joerg Exp $ */ + +/*- + * Copyright (c) 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include + +char * +fgetln(fp, len) + FILE *fp; + size_t *len; +{ + static char *buf = NULL; + static size_t bufsiz = 0; + char *ptr; + + + if (buf == NULL) { + bufsiz = BUFSIZ; + if ((buf = malloc(bufsiz)) == NULL) + return NULL; + } + + if (fgets(buf, bufsiz, fp) == NULL) + return NULL; + + *len = 0; + while ((ptr = strchr(&buf[*len], '\n')) == NULL) { + size_t nbufsiz = bufsiz + BUFSIZ; + char *nbuf = realloc(buf, nbufsiz); + + if (nbuf == NULL) { + int oerrno = errno; + free(buf); + errno = oerrno; + buf = NULL; + return NULL; + } else + buf = nbuf; + + *len = bufsiz; + if (fgets(&buf[bufsiz], BUFSIZ, fp) == NULL) + return buf; + + bufsiz = nbufsiz; + } + + *len = (ptr - buf) + 1; + return buf; +} + +#endif diff --git a/external/bsd/mdocml/dist/compat_getsubopt.c b/external/bsd/mdocml/dist/compat_getsubopt.c new file mode 100644 index 000000000..9cd415367 --- /dev/null +++ b/external/bsd/mdocml/dist/compat_getsubopt.c @@ -0,0 +1,104 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_GETSUBOPT + +int dummy; + +#else + +/* $OpenBSD: getsubopt.c,v 1.4 2005/08/08 08:05:36 espie Exp $ */ + +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include + +/* + * The SVID interface to getsubopt provides no way of figuring out which + * part of the suboptions list wasn't matched. This makes error messages + * tricky... The extern variable suboptarg is a pointer to the token + * which didn't match. + */ +char *suboptarg; + +int +getsubopt(char **optionp, char * const *tokens, char **valuep) +{ + int cnt; + char *p; + + suboptarg = *valuep = NULL; + + if (!optionp || !*optionp) + return(-1); + + /* skip leading white-space, commas */ + for (p = *optionp; *p && (*p == ',' || *p == ' ' || *p == '\t'); ++p); + + if (!*p) { + *optionp = p; + return(-1); + } + + /* save the start of the token, and skip the rest of the token. */ + for (suboptarg = p; + *++p && *p != ',' && *p != '=' && *p != ' ' && *p != '\t';); + + if (*p) { + /* + * If there's an equals sign, set the value pointer, and + * skip over the value part of the token. Terminate the + * token. + */ + if (*p == '=') { + *p = '\0'; + for (*valuep = ++p; + *p && *p != ',' && *p != ' ' && *p != '\t'; ++p); + if (*p) + *p++ = '\0'; + } else + *p++ = '\0'; + /* Skip any whitespace or commas after this token. */ + for (; *p && (*p == ',' || *p == ' ' || *p == '\t'); ++p); + } + + /* set optionp for next round. */ + *optionp = p; + + for (cnt = 0; *tokens; ++tokens, ++cnt) + if (!strcmp(suboptarg, *tokens)) + return(cnt); + return(-1); +} + +#endif diff --git a/external/bsd/mdocml/dist/compat.c b/external/bsd/mdocml/dist/compat_strlcat.c similarity index 70% rename from external/bsd/mdocml/dist/compat.c rename to external/bsd/mdocml/dist/compat_strlcat.c index f00cc5c6b..543d40b38 100644 --- a/external/bsd/mdocml/dist/compat.c +++ b/external/bsd/mdocml/dist/compat_strlcat.c @@ -1,3 +1,13 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_STRLCAT + +int dummy; + +#else + /* $OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $ */ /* @@ -15,16 +25,10 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif #include #include -int dummy; /* To prevent an empty object file */ - -#ifndef HAVE_STRLCAT /* * Appends src to string dst of size siz (unlike strncat, siz is the * full size of dst, not space left). At most siz-1 characters @@ -59,37 +63,5 @@ strlcat(char *dst, const char *src, size_t siz) return(dlen + (s - src)); /* count does not include NUL */ } + #endif - -#ifndef HAVE_STRLCPY -/* - * Copy src to string dst of size siz. At most siz-1 characters - * will be copied. Always NUL terminates (unless siz == 0). - * Returns strlen(src); if retval >= siz, truncation occurred. - */ -size_t -strlcpy(char *dst, const char *src, size_t siz) -{ - char *d = dst; - const char *s = src; - size_t n = siz; - - /* Copy as many bytes as will fit */ - if (n != 0) { - while (--n != 0) { - if ((*d++ = *s++) == '\0') - break; - } - } - - /* Not enough room in dst, add NUL and traverse rest of src */ - if (n == 0) { - if (siz != 0) - *d = '\0'; /* NUL-terminate dst */ - while (*s++) - ; - } - - return(s - src - 1); /* count does not include NUL */ -} -#endif diff --git a/external/bsd/mdocml/dist/compat_strlcpy.c b/external/bsd/mdocml/dist/compat_strlcpy.c new file mode 100644 index 000000000..a7c64ff99 --- /dev/null +++ b/external/bsd/mdocml/dist/compat_strlcpy.c @@ -0,0 +1,63 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_STRLCPY + +int dummy; + +#else + +/* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */ + +/* + * Copyright (c) 1998 Todd C. Miller + * + * 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 +#include + +/* + * Copy src to string dst of size siz. At most siz-1 characters + * will be copied. Always NUL terminates (unless siz == 0). + * Returns strlen(src); if retval >= siz, truncation occurred. + */ +size_t +strlcpy(char *dst, const char *src, size_t siz) +{ + char *d = dst; + const char *s = src; + size_t n = siz; + + /* Copy as many bytes as will fit */ + if (n != 0) { + while (--n != 0) { + if ((*d++ = *s++) == '\0') + break; + } + } + + /* Not enough room in dst, add NUL and traverse rest of src */ + if (n == 0) { + if (siz != 0) + *d = '\0'; /* NUL-terminate dst */ + while (*s++) + ; + } + + return(s - src - 1); /* count does not include NUL */ +} + +#endif diff --git a/external/bsd/mdocml/dist/config.h.post b/external/bsd/mdocml/dist/config.h.post index 81c01b931..39da2b2f0 100644 --- a/external/bsd/mdocml/dist/config.h.post +++ b/external/bsd/mdocml/dist/config.h.post @@ -15,11 +15,28 @@ # endif #endif +#if defined(__APPLE__) +# define htobe32(x) OSSwapHostToBigInt32(x) +# define betoh32(x) OSSwapBigToHostInt32(x) +# define htobe64(x) OSSwapHostToBigInt64(x) +# define betoh64(x) OSSwapBigToHostInt64(x) +#elif defined(__linux__) +# define betoh32(x) be32toh(x) +# define betoh64(x) be64toh(x) +#endif + #ifndef HAVE_STRLCAT extern size_t strlcat(char *, const char *, size_t); #endif #ifndef HAVE_STRLCPY extern size_t strlcpy(char *, const char *, size_t); #endif +#ifndef HAVE_GETSUBOPT +extern int getsubopt(char **, char * const *, char **); +extern char *suboptarg; +#endif +#ifndef HAVE_FGETLN +extern char *fgetln(FILE *, size_t *); +#endif #endif /* MANDOC_CONFIG_H */ diff --git a/external/bsd/mdocml/dist/config.h.pre b/external/bsd/mdocml/dist/config.h.pre index a309ed956..bc5947848 100644 --- a/external/bsd/mdocml/dist/config.h.pre +++ b/external/bsd/mdocml/dist/config.h.pre @@ -4,3 +4,5 @@ #if defined(__linux__) || defined(__MINT__) # define _GNU_SOURCE /* strptime(), getsubopt() */ #endif + +#include diff --git a/external/bsd/mdocml/dist/demandoc.1 b/external/bsd/mdocml/dist/demandoc.1 new file mode 100644 index 000000000..62c70db14 --- /dev/null +++ b/external/bsd/mdocml/dist/demandoc.1 @@ -0,0 +1,109 @@ +.\" $Vendor-Id: demandoc.1,v 1.6 2011/12/25 19:35:44 kristaps Exp $ +.\" +.\" Copyright (c) 2011 Kristaps Dzonsons +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd December 25, 2011 +.Dt DEMANDOC 1 +.Os +.Sh NAME +.Nm demandoc +.Nd emit only text of UNIX manuals +.Sh SYNOPSIS +.Nm demandoc +.Op Fl w +.Op Ar +.Sh DESCRIPTION +The +.Nm +utility emits only the text portions of well-formed +.Xr mdoc 7 +and +.Xr man 7 +.Ux +manual files. +.Pp +By default, +.Nm +parses standard input and outputs only text nodes, preserving line +and column position. +Escape sequences are omitted from the output. +.Pp +Its arguments are as follows: +.Bl -tag -width Ds +.It Fl w +Output a word list. +This outputs each word of text on its own line. +A +.Qq word , +in this case, refers to whitespace-delimited terms beginning with at +least two letters and not consisting of any escape sequences. +Words have their leading and trailing punctuation +.Pq double-quotes, sentence punctuation, etc. +stripped. +.It Ar +The input files. +.El +.Pp +If a document is not well-formed, it is skipped. +.Pp +The +.Fl i , +.Fl k , +.Fl m , +and +.Fl p +flags are silently discarded for calling compatibility with the +historical deroff. +.Sh EXIT STATUS +The +.Nm +utility exits with one of the following values: +.Pp +.Bl -tag -width Ds -compact +.It 0 +No errors occurred. +.It 6 +An operating system error occurred, for example memory exhaustion or an +error accessing input files. +Such errors cause +.Nm +to exit at once, possibly in the middle of parsing or formatting a file. +The output databases are corrupt and should be removed . +.El +.Sh EXAMPLES +The traditional usage of +.Nm +is for spell-checking manuals on +.Bx . +This is accomplished as follows (assuming British spelling): +.Pp +.Dl $ demandoc -w file.1 | spell -b +.Sh SEE ALSO +.Xr mandoc 1 , +.Xr man 7 +.Xr mdoc 7 +.Sh HISTORY +.Nm +replaces the historical deroff utility for handling modern +.Xr man 7 +and +.Xr mdoc 7 +documents. +.Sh AUTHORS +The +.Nm +utility was written by +.An Kristaps Dzonsons , +.Mt kristaps@bsd.lv . diff --git a/external/bsd/mdocml/dist/demandoc.c b/external/bsd/mdocml/dist/demandoc.c new file mode 100644 index 000000000..28b145c8b --- /dev/null +++ b/external/bsd/mdocml/dist/demandoc.c @@ -0,0 +1,257 @@ +/* $Vendor-Id: demandoc.c,v 1.6 2011/09/01 22:25:53 kristaps Exp $ */ +/* + * Copyright (c) 2011 Kristaps Dzonsons + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "man.h" +#include "mdoc.h" +#include "mandoc.h" + +static void pline(int, int *, int *, int); +static void pman(const struct man_node *, int *, int *, int); +static void pmandoc(struct mparse *, int, const char *, int); +static void pmdoc(const struct mdoc_node *, int *, int *, int); +static void pstring(const char *, int, int *, int); +static void usage(void); + +static const char *progname; + +int +main(int argc, char *argv[]) +{ + struct mparse *mp; + int ch, i, list; + extern int optind; + + progname = strrchr(argv[0], '/'); + if (progname == NULL) + progname = argv[0]; + else + ++progname; + + mp = NULL; + list = 0; + + while (-1 != (ch = getopt(argc, argv, "ikm:pw"))) + switch (ch) { + case ('i'): + /* FALLTHROUGH */ + case ('k'): + /* FALLTHROUGH */ + case ('m'): + /* FALLTHROUGH */ + case ('p'): + break; + case ('w'): + list = 1; + break; + default: + usage(); + return((int)MANDOCLEVEL_BADARG); + } + + argc -= optind; + argv += optind; + + mp = mparse_alloc(MPARSE_AUTO, MANDOCLEVEL_FATAL, NULL, NULL); + assert(mp); + + if (0 == argc) + pmandoc(mp, STDIN_FILENO, "", list); + + for (i = 0; i < argc; i++) { + mparse_reset(mp); + pmandoc(mp, -1, argv[i], list); + } + + mparse_free(mp); + return((int)MANDOCLEVEL_OK); +} + +static void +usage(void) +{ + + fprintf(stderr, "usage: %s [-w] [files...]\n", progname); +} + +static void +pmandoc(struct mparse *mp, int fd, const char *fn, int list) +{ + struct mdoc *mdoc; + struct man *man; + int line, col; + + if (mparse_readfd(mp, fd, fn) >= MANDOCLEVEL_FATAL) { + fprintf(stderr, "%s: Parse failure\n", fn); + return; + } + + mparse_result(mp, &mdoc, &man); + line = 1; + col = 0; + + if (mdoc) + pmdoc(mdoc_node(mdoc), &line, &col, list); + else if (man) + pman(man_node(man), &line, &col, list); + else + return; + + if ( ! list) + putchar('\n'); +} + +/* + * Strip the escapes out of a string, emitting the results. + */ +static void +pstring(const char *p, int col, int *colp, int list) +{ + enum mandoc_esc esc; + const char *start, *end; + int emit; + + /* + * Print as many column spaces til we achieve parity with the + * input document. + */ + +again: + if (list && '\0' != *p) { + while (isspace((unsigned char)*p)) + p++; + + while ('\'' == *p || '(' == *p || '"' == *p) + p++; + + emit = isalpha((unsigned char)p[0]) && + isalpha((unsigned char)p[1]); + + for (start = p; '\0' != *p; p++) + if ('\\' == *p) { + p++; + esc = mandoc_escape(&p, NULL, NULL); + if (ESCAPE_ERROR == esc) + return; + emit = 0; + } else if (isspace((unsigned char)*p)) + break; + + end = p - 1; + + while (end > start) + if ('.' == *end || ',' == *end || + '\'' == *end || '"' == *end || + ')' == *end || '!' == *end || + '?' == *end || ':' == *end || + ';' == *end) + end--; + else + break; + + if (emit && end - start >= 1) { + for ( ; start <= end; start++) + if (ASCII_HYPH == *start) + putchar('-'); + else + putchar((unsigned char)*start); + putchar('\n'); + } + + if (isspace((unsigned char)*p)) + goto again; + + return; + } + + while (*colp < col) { + putchar(' '); + (*colp)++; + } + + /* + * Print the input word, skipping any special characters. + */ + while ('\0' != *p) + if ('\\' == *p) { + p++; + esc = mandoc_escape(&p, NULL, NULL); + if (ESCAPE_ERROR == esc) + break; + } else { + putchar((unsigned char )*p++); + (*colp)++; + } +} + +static void +pline(int line, int *linep, int *col, int list) +{ + + if (list) + return; + + /* + * Print out as many lines as needed to reach parity with the + * original input. + */ + + while (*linep < line) { + putchar('\n'); + (*linep)++; + } + + *col = 0; +} + +static void +pmdoc(const struct mdoc_node *p, int *line, int *col, int list) +{ + + for ( ; p; p = p->next) { + if (MDOC_LINE & p->flags) + pline(p->line, line, col, list); + if (MDOC_TEXT == p->type) + pstring(p->string, p->pos, col, list); + if (p->child) + pmdoc(p->child, line, col, list); + } +} + +static void +pman(const struct man_node *p, int *line, int *col, int list) +{ + + for ( ; p; p = p->next) { + if (MAN_LINE & p->flags) + pline(p->line, line, col, list); + if (MAN_TEXT == p->type) + pstring(p->string, p->pos, col, list); + if (p->child) + pman(p->child, line, col, list); + } +} diff --git a/external/bsd/mdocml/dist/eqn.7 b/external/bsd/mdocml/dist/eqn.7 new file mode 100644 index 000000000..489107c16 --- /dev/null +++ b/external/bsd/mdocml/dist/eqn.7 @@ -0,0 +1,280 @@ +.\" $Vendor-Id: eqn.7,v 1.28 2011/09/25 18:37:09 schwarze Exp $ +.\" +.\" Copyright (c) 2011 Kristaps Dzonsons +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd September 25, 2011 +.Dt EQN 7 +.Os +.Sh NAME +.Nm eqn +.Nd eqn language reference for mandoc +.Sh DESCRIPTION +The +.Nm eqn +language is an equation-formatting language. +It is used within +.Xr mdoc 7 +and +.Xr man 7 +.Ux +manual pages. +It describes the +.Em structure +of an equation, not its mathematical meaning. +This manual describes the +.Nm +language accepted by the +.Xr mandoc 1 +utility, which corresponds to the Second Edition eqn specification (see +.Sx SEE ALSO +for references). +.Pp +Equations within +.Xr mdoc 7 +or +.Xr man 7 +documents are enclosed by the standalone +.Sq \&.EQ +and +.Sq \&.EN +tags. +Equations are multi-line blocks consisting of formulas and control +statements. +.Sh EQUATION STRUCTURE +Each equation is bracketed by +.Sq \&.EQ +and +.Sq \&.EN +strings. +.Em Note : +these are not the same as +.Xr roff 7 +macros, and may only be invoked as +.Sq \&.EQ . +.Pp +The equation grammar is as follows, where quoted strings are +case-sensitive literals in the input: +.Bd -literal -offset indent +eqn : box | eqn box +box : text + | \*q{\*q eqn \*q}\*q + | \*qdefine\*q text text + | \*qndefine\*q text text + | \*qtdefine\*q text text + | \*qgfont\*q text + | \*qgsize\*q text + | \*qset\*q text text + | \*qundef\*q text + | box pos box + | box mark + | \*qmatrix\*q \*q{\*q [col \*q{\*q list \*q}\*q ]* + | pile \*q{\*q list \*q}\*q + | font box + | \*qsize\*q text box + | \*qleft\*q text eqn [\*qright\*q text] +col : \*qlcol\*q | \*qrcol\*q | \*qccol\*q | \*qcol\*q +text : [^space\e\*q]+ | \e\*q.*\e\*q +pile : \*qlpile\*q | \*qcpile\*q | \*qrpile\*q | \*qpile\*q +pos : \*qover\*q | \*qsup\*q | \*qsub\*q | \*qto\*q | \*qfrom\*q +mark : \*qdot\*q | \*qdotdot\*q | \*qhat\*q | \*qtilde\*q | \*qvec\*q + | \*qdyad\*q | \*qbar\*q | \*qunder\*q +font : \*qroman\*q | \*qitalic\*q | \*qbold\*q | \*qfat\*q +list : eqn + | list \*qabove\*q eqn +space : [\e^~ \et] +.Ed +.Pp +White-space consists of the space, tab, circumflex, and tilde +characters. +If within a quoted string, these space characters are retained. +Quoted strings are also not scanned for replacement definitions. +.Pp +The following text terms are translated into a rendered glyph, if +available: alpha, beta, chi, delta, epsilon, eta, gamma, iota, kappa, +lambda, mu, nu, omega, omicron, phi, pi, psi, rho, sigma, tau, theta, +upsilon, xi, zeta, DELTA, GAMMA, LAMBDA, OMEGA, PHI, PI, PSI, SIGMA, +THETA, UPSILON, XI, inter (intersection), union (union), prod (product), +int (integral), sum (summation), grad (gradient), del (vector +differential), times (multiply), cdot (centre-dot), nothing (zero-width +space), approx (approximately equals), prime (prime), half (one-half), +partial (partial differential), inf (infinity), >> (much greater), << +(much less), \-> (left arrow), <\- (right arrow), += (plus-minus), != +(not equal), == (equivalence), <= (less-than-equal), and >= +(more-than-equal). +.Pp +The following control statements are available: +.Bl -tag -width Ds +.It Cm define +Replace all occurrences of a key with a value. +Its syntax is as follows: +.Pp +.D1 define Ar key cvalc +.Pp +The first character of the value string, +.Ar c , +is used as the delimiter for the value +.Ar val . +This allows for arbitrary enclosure of terms (not just quotes), such as +.Pp +.D1 define Ar foo 'bar baz' +.D1 define Ar foo cbar bazc +.Pp +It is an error to have an empty +.Ar key +or +.Ar val . +Note that a quoted +.Ar key +causes errors in some +.Nm +implementations and should not be considered portable. +It is not expanded for replacements. +Definitions may refer to other definitions; these are evaluated +recursively when text replacement occurs and not when the definition is +created. +.Pp +Definitions can create arbitrary strings, for example, the following is +a legal construction. +.Bd -literal -offset indent +define foo 'define' +foo bar 'baz' +.Ed +.Pp +Self-referencing definitions will raise an error. +The +.Cm ndefine +statement is a synonym for +.Cm define , +while +.Cm tdefine +is discarded. +.It Cm gfont +Set the default font of subsequent output. +Its syntax is as follows: +.Pp +.D1 gfont Ar font +.Pp +In mandoc, this value is discarded. +.It Cm gsize +Set the default size of subsequent output. +Its syntax is as follows: +.Pp +.D1 gsize Ar size +.Pp +The +.Ar size +value should be an integer. +.It Cm set +Set an equation mode. +In mandoc, both arguments are thrown away. +Its syntax is as follows: +.Pp +.D1 set Ar key val +.Pp +The +.Ar key +and +.Ar val +are not expanded for replacements. +This statement is a GNU extension. +.It Cm undef +Unset a previously-defined key. +Its syntax is as follows: +.Pp +.D1 define Ar key +.Pp +Once invoked, the definition for +.Ar key +is discarded. +The +.Ar key +is not expanded for replacements. +This statement is a GNU extension. +.El +.Sh COMPATIBILITY +This section documents the compatibility of mandoc +.Nm +and the troff +.Nm +implementation (including GNU troff). +.Pp +.Bl -dash -compact +.It +The text string +.Sq \e\*q +is interpreted as a literal quote in troff. +In mandoc, this is interpreted as a comment. +.It +In troff, The circumflex and tilde white-space symbols map to +fixed-width spaces. +In mandoc, these characters are synonyms for the space character. +.It +The troff implementation of +.Nm +allows for equation alignment with the +.Cm mark +and +.Cm lineup +tokens. +mandoc discards these tokens. +The +.Cm back Ar n , +.Cm fwd Ar n , +.Cm up Ar n , +and +.Cm down Ar n +commands are also ignored. +.El +.Sh SEE ALSO +.Xr mandoc 1 , +.Xr man 7 , +.Xr mandoc_char 7 , +.Xr mdoc 7 , +.Xr roff 7 +.Rs +.%A Brian W. Kernighan +.%A Lorinda L. Cherry +.%T System for Typesetting Mathematics +.%J Communications of the ACM +.%V 18 +.%P 151\(en157 +.%D March, 1975 +.Re +.Rs +.%A Brian W. Kernighan +.%A Lorinda L. Cherry +.%T Typesetting Mathematics, User's Guide +.%D 1976 +.Re +.Rs +.%A Brian W. Kernighan +.%A Lorinda L. Cherry +.%T Typesetting Mathematics, User's Guide (Second Edition) +.%D 1978 +.Re +.Sh HISTORY +The eqn utility, a preprocessor for troff, was originally written by +Brian W. Kernighan and Lorinda L. Cherry in 1975. +The GNU reimplementation of eqn, part of the GNU troff package, was +released in 1989 by James Clark. +The eqn component of +.Xr mandoc 1 +was added in 2011. +.Sh AUTHORS +This +.Nm +reference was written by +.An Kristaps Dzonsons , +.Mt kristaps@bsd.lv . diff --git a/external/bsd/mdocml/dist/eqn.c b/external/bsd/mdocml/dist/eqn.c new file mode 100644 index 000000000..d57eabbb8 --- /dev/null +++ b/external/bsd/mdocml/dist/eqn.c @@ -0,0 +1,949 @@ +/* $Vendor-Id: eqn.c,v 1.38 2011/07/25 15:37:00 kristaps Exp $ */ +/* + * Copyright (c) 2011 Kristaps Dzonsons + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include + +#include "mandoc.h" +#include "libmandoc.h" +#include "libroff.h" + +#define EQN_NEST_MAX 128 /* maximum nesting of defines */ +#define EQN_MSG(t, x) mandoc_msg((t), (x)->parse, (x)->eqn.ln, (x)->eqn.pos, NULL) + +enum eqn_rest { + EQN_DESCOPE, + EQN_ERR, + EQN_OK, + EQN_EOF +}; + +enum eqn_symt { + EQNSYM_alpha, + EQNSYM_beta, + EQNSYM_chi, + EQNSYM_delta, + EQNSYM_epsilon, + EQNSYM_eta, + EQNSYM_gamma, + EQNSYM_iota, + EQNSYM_kappa, + EQNSYM_lambda, + EQNSYM_mu, + EQNSYM_nu, + EQNSYM_omega, + EQNSYM_omicron, + EQNSYM_phi, + EQNSYM_pi, + EQNSYM_ps, + EQNSYM_rho, + EQNSYM_sigma, + EQNSYM_tau, + EQNSYM_theta, + EQNSYM_upsilon, + EQNSYM_xi, + EQNSYM_zeta, + EQNSYM_DELTA, + EQNSYM_GAMMA, + EQNSYM_LAMBDA, + EQNSYM_OMEGA, + EQNSYM_PHI, + EQNSYM_PI, + EQNSYM_PSI, + EQNSYM_SIGMA, + EQNSYM_THETA, + EQNSYM_UPSILON, + EQNSYM_XI, + EQNSYM_inter, + EQNSYM_union, + EQNSYM_prod, + EQNSYM_int, + EQNSYM_sum, + EQNSYM_grad, + EQNSYM_del, + EQNSYM_times, + EQNSYM_cdot, + EQNSYM_nothing, + EQNSYM_approx, + EQNSYM_prime, + EQNSYM_half, + EQNSYM_partial, + EQNSYM_inf, + EQNSYM_muchgreat, + EQNSYM_muchless, + EQNSYM_larrow, + EQNSYM_rarrow, + EQNSYM_pm, + EQNSYM_nequal, + EQNSYM_equiv, + EQNSYM_lessequal, + EQNSYM_moreequal, + EQNSYM__MAX +}; + +enum eqnpartt { + EQN_DEFINE = 0, + EQN_NDEFINE, + EQN_TDEFINE, + EQN_SET, + EQN_UNDEF, + EQN_GFONT, + EQN_GSIZE, + EQN_BACK, + EQN_FWD, + EQN_UP, + EQN_DOWN, + EQN__MAX +}; + +struct eqnstr { + const char *name; + size_t sz; +}; + +#define STRNEQ(p1, sz1, p2, sz2) \ + ((sz1) == (sz2) && 0 == strncmp((p1), (p2), (sz1))) +#define EQNSTREQ(x, p, sz) \ + STRNEQ((x)->name, (x)->sz, (p), (sz)) + +struct eqnpart { + struct eqnstr str; + int (*fp)(struct eqn_node *); +}; + +struct eqnsym { + struct eqnstr str; + const char *sym; +}; + + +static enum eqn_rest eqn_box(struct eqn_node *, struct eqn_box *); +static struct eqn_box *eqn_box_alloc(struct eqn_node *, + struct eqn_box *); +static void eqn_box_free(struct eqn_box *); +static struct eqn_def *eqn_def_find(struct eqn_node *, + const char *, size_t); +static int eqn_do_gfont(struct eqn_node *); +static int eqn_do_gsize(struct eqn_node *); +static int eqn_do_define(struct eqn_node *); +static int eqn_do_ign1(struct eqn_node *); +static int eqn_do_ign2(struct eqn_node *); +static int eqn_do_tdefine(struct eqn_node *); +static int eqn_do_undef(struct eqn_node *); +static enum eqn_rest eqn_eqn(struct eqn_node *, struct eqn_box *); +static enum eqn_rest eqn_list(struct eqn_node *, struct eqn_box *); +static enum eqn_rest eqn_matrix(struct eqn_node *, struct eqn_box *); +static const char *eqn_nexttok(struct eqn_node *, size_t *); +static const char *eqn_nextrawtok(struct eqn_node *, size_t *); +static const char *eqn_next(struct eqn_node *, + char, size_t *, int); +static void eqn_rewind(struct eqn_node *); + +static const struct eqnpart eqnparts[EQN__MAX] = { + { { "define", 6 }, eqn_do_define }, /* EQN_DEFINE */ + { { "ndefine", 7 }, eqn_do_define }, /* EQN_NDEFINE */ + { { "tdefine", 7 }, eqn_do_tdefine }, /* EQN_TDEFINE */ + { { "set", 3 }, eqn_do_ign2 }, /* EQN_SET */ + { { "undef", 5 }, eqn_do_undef }, /* EQN_UNDEF */ + { { "gfont", 5 }, eqn_do_gfont }, /* EQN_GFONT */ + { { "gsize", 5 }, eqn_do_gsize }, /* EQN_GSIZE */ + { { "back", 4 }, eqn_do_ign1 }, /* EQN_BACK */ + { { "fwd", 3 }, eqn_do_ign1 }, /* EQN_FWD */ + { { "up", 2 }, eqn_do_ign1 }, /* EQN_UP */ + { { "down", 4 }, eqn_do_ign1 }, /* EQN_DOWN */ +}; + +static const struct eqnstr eqnmarks[EQNMARK__MAX] = { + { "", 0 }, /* EQNMARK_NONE */ + { "dot", 3 }, /* EQNMARK_DOT */ + { "dotdot", 6 }, /* EQNMARK_DOTDOT */ + { "hat", 3 }, /* EQNMARK_HAT */ + { "tilde", 5 }, /* EQNMARK_TILDE */ + { "vec", 3 }, /* EQNMARK_VEC */ + { "dyad", 4 }, /* EQNMARK_DYAD */ + { "bar", 3 }, /* EQNMARK_BAR */ + { "under", 5 }, /* EQNMARK_UNDER */ +}; + +static const struct eqnstr eqnfonts[EQNFONT__MAX] = { + { "", 0 }, /* EQNFONT_NONE */ + { "roman", 5 }, /* EQNFONT_ROMAN */ + { "bold", 4 }, /* EQNFONT_BOLD */ + { "fat", 3 }, /* EQNFONT_FAT */ + { "italic", 6 }, /* EQNFONT_ITALIC */ +}; + +static const struct eqnstr eqnposs[EQNPOS__MAX] = { + { "", 0 }, /* EQNPOS_NONE */ + { "over", 4 }, /* EQNPOS_OVER */ + { "sup", 3 }, /* EQNPOS_SUP */ + { "sub", 3 }, /* EQNPOS_SUB */ + { "to", 2 }, /* EQNPOS_TO */ + { "from", 4 }, /* EQNPOS_FROM */ +}; + +static const struct eqnstr eqnpiles[EQNPILE__MAX] = { + { "", 0 }, /* EQNPILE_NONE */ + { "pile", 4 }, /* EQNPILE_PILE */ + { "cpile", 5 }, /* EQNPILE_CPILE */ + { "rpile", 5 }, /* EQNPILE_RPILE */ + { "lpile", 5 }, /* EQNPILE_LPILE */ + { "col", 3 }, /* EQNPILE_COL */ + { "ccol", 4 }, /* EQNPILE_CCOL */ + { "rcol", 4 }, /* EQNPILE_RCOL */ + { "lcol", 4 }, /* EQNPILE_LCOL */ +}; + +static const struct eqnsym eqnsyms[EQNSYM__MAX] = { + { { "alpha", 5 }, "*a" }, /* EQNSYM_alpha */ + { { "beta", 4 }, "*b" }, /* EQNSYM_beta */ + { { "chi", 3 }, "*x" }, /* EQNSYM_chi */ + { { "delta", 5 }, "*d" }, /* EQNSYM_delta */ + { { "epsilon", 7 }, "*e" }, /* EQNSYM_epsilon */ + { { "eta", 3 }, "*y" }, /* EQNSYM_eta */ + { { "gamma", 5 }, "*g" }, /* EQNSYM_gamma */ + { { "iota", 4 }, "*i" }, /* EQNSYM_iota */ + { { "kappa", 5 }, "*k" }, /* EQNSYM_kappa */ + { { "lambda", 6 }, "*l" }, /* EQNSYM_lambda */ + { { "mu", 2 }, "*m" }, /* EQNSYM_mu */ + { { "nu", 2 }, "*n" }, /* EQNSYM_nu */ + { { "omega", 5 }, "*w" }, /* EQNSYM_omega */ + { { "omicron", 7 }, "*o" }, /* EQNSYM_omicron */ + { { "phi", 3 }, "*f" }, /* EQNSYM_phi */ + { { "pi", 2 }, "*p" }, /* EQNSYM_pi */ + { { "psi", 2 }, "*q" }, /* EQNSYM_psi */ + { { "rho", 3 }, "*r" }, /* EQNSYM_rho */ + { { "sigma", 5 }, "*s" }, /* EQNSYM_sigma */ + { { "tau", 3 }, "*t" }, /* EQNSYM_tau */ + { { "theta", 5 }, "*h" }, /* EQNSYM_theta */ + { { "upsilon", 7 }, "*u" }, /* EQNSYM_upsilon */ + { { "xi", 2 }, "*c" }, /* EQNSYM_xi */ + { { "zeta", 4 }, "*z" }, /* EQNSYM_zeta */ + { { "DELTA", 5 }, "*D" }, /* EQNSYM_DELTA */ + { { "GAMMA", 5 }, "*G" }, /* EQNSYM_GAMMA */ + { { "LAMBDA", 6 }, "*L" }, /* EQNSYM_LAMBDA */ + { { "OMEGA", 5 }, "*W" }, /* EQNSYM_OMEGA */ + { { "PHI", 3 }, "*F" }, /* EQNSYM_PHI */ + { { "PI", 2 }, "*P" }, /* EQNSYM_PI */ + { { "PSI", 3 }, "*Q" }, /* EQNSYM_PSI */ + { { "SIGMA", 5 }, "*S" }, /* EQNSYM_SIGMA */ + { { "THETA", 5 }, "*H" }, /* EQNSYM_THETA */ + { { "UPSILON", 7 }, "*U" }, /* EQNSYM_UPSILON */ + { { "XI", 2 }, "*C" }, /* EQNSYM_XI */ + { { "inter", 5 }, "ca" }, /* EQNSYM_inter */ + { { "union", 5 }, "cu" }, /* EQNSYM_union */ + { { "prod", 4 }, "product" }, /* EQNSYM_prod */ + { { "int", 3 }, "integral" }, /* EQNSYM_int */ + { { "sum", 3 }, "sum" }, /* EQNSYM_sum */ + { { "grad", 4 }, "gr" }, /* EQNSYM_grad */ + { { "del", 3 }, "gr" }, /* EQNSYM_del */ + { { "times", 5 }, "mu" }, /* EQNSYM_times */ + { { "cdot", 4 }, "pc" }, /* EQNSYM_cdot */ + { { "nothing", 7 }, "&" }, /* EQNSYM_nothing */ + { { "approx", 6 }, "~~" }, /* EQNSYM_approx */ + { { "prime", 5 }, "aq" }, /* EQNSYM_prime */ + { { "half", 4 }, "12" }, /* EQNSYM_half */ + { { "partial", 7 }, "pd" }, /* EQNSYM_partial */ + { { "inf", 3 }, "if" }, /* EQNSYM_inf */ + { { ">>", 2 }, ">>" }, /* EQNSYM_muchgreat */ + { { "<<", 2 }, "<<" }, /* EQNSYM_muchless */ + { { "<-", 2 }, "<-" }, /* EQNSYM_larrow */ + { { "->", 2 }, "->" }, /* EQNSYM_rarrow */ + { { "+-", 2 }, "+-" }, /* EQNSYM_pm */ + { { "!=", 2 }, "!=" }, /* EQNSYM_nequal */ + { { "==", 2 }, "==" }, /* EQNSYM_equiv */ + { { "<=", 2 }, "<=" }, /* EQNSYM_lessequal */ + { { ">=", 2 }, ">=" }, /* EQNSYM_moreequal */ +}; + +/* ARGSUSED */ +enum rofferr +eqn_read(struct eqn_node **epp, int ln, + const char *p, int pos, int *offs) +{ + size_t sz; + struct eqn_node *ep; + enum rofferr er; + + ep = *epp; + + /* + * If we're the terminating mark, unset our equation status and + * validate the full equation. + */ + + if (0 == strncmp(p, ".EN", 3)) { + er = eqn_end(epp); + p += 3; + while (' ' == *p || '\t' == *p) + p++; + if ('\0' == *p) + return(er); + mandoc_msg(MANDOCERR_ARGSLOST, ep->parse, ln, pos, NULL); + return(er); + } + + /* + * Build up the full string, replacing all newlines with regular + * whitespace. + */ + + sz = strlen(p + pos) + 1; + ep->data = mandoc_realloc(ep->data, ep->sz + sz + 1); + + /* First invocation: nil terminate the string. */ + + if (0 == ep->sz) + *ep->data = '\0'; + + ep->sz += sz; + strlcat(ep->data, p + pos, ep->sz + 1); + strlcat(ep->data, " ", ep->sz + 1); + return(ROFF_IGN); +} + +struct eqn_node * +eqn_alloc(const char *name, int pos, int line, struct mparse *parse) +{ + struct eqn_node *p; + size_t sz; + const char *end; + + p = mandoc_calloc(1, sizeof(struct eqn_node)); + + if (name && '\0' != *name) { + sz = strlen(name); + assert(sz); + do { + sz--; + end = name + (int)sz; + } while (' ' == *end || '\t' == *end); + p->eqn.name = mandoc_strndup(name, sz + 1); + } + + p->parse = parse; + p->eqn.ln = line; + p->eqn.pos = pos; + p->gsize = EQN_DEFSIZE; + + return(p); +} + +enum rofferr +eqn_end(struct eqn_node **epp) +{ + struct eqn_node *ep; + struct eqn_box *root; + enum eqn_rest c; + + ep = *epp; + *epp = NULL; + + ep->eqn.root = mandoc_calloc(1, sizeof(struct eqn_box)); + + root = ep->eqn.root; + root->type = EQN_ROOT; + + if (0 == ep->sz) + return(ROFF_IGN); + + if (EQN_DESCOPE == (c = eqn_eqn(ep, root))) { + EQN_MSG(MANDOCERR_EQNNSCOPE, ep); + c = EQN_ERR; + } + + return(EQN_EOF == c ? ROFF_EQN : ROFF_IGN); +} + +static enum eqn_rest +eqn_eqn(struct eqn_node *ep, struct eqn_box *last) +{ + struct eqn_box *bp; + enum eqn_rest c; + + bp = eqn_box_alloc(ep, last); + bp->type = EQN_SUBEXPR; + + while (EQN_OK == (c = eqn_box(ep, bp))) + /* Spin! */ ; + + return(c); +} + +static enum eqn_rest +eqn_matrix(struct eqn_node *ep, struct eqn_box *last) +{ + struct eqn_box *bp; + const char *start; + size_t sz; + enum eqn_rest c; + + bp = eqn_box_alloc(ep, last); + bp->type = EQN_MATRIX; + + if (NULL == (start = eqn_nexttok(ep, &sz))) { + EQN_MSG(MANDOCERR_EQNEOF, ep); + return(EQN_ERR); + } + if ( ! STRNEQ(start, sz, "{", 1)) { + EQN_MSG(MANDOCERR_EQNSYNT, ep); + return(EQN_ERR); + } + + while (EQN_OK == (c = eqn_box(ep, bp))) + switch (bp->last->pile) { + case (EQNPILE_LCOL): + /* FALLTHROUGH */ + case (EQNPILE_CCOL): + /* FALLTHROUGH */ + case (EQNPILE_RCOL): + continue; + default: + EQN_MSG(MANDOCERR_EQNSYNT, ep); + return(EQN_ERR); + }; + + if (EQN_DESCOPE != c) { + if (EQN_EOF == c) + EQN_MSG(MANDOCERR_EQNEOF, ep); + return(EQN_ERR); + } + + eqn_rewind(ep); + start = eqn_nexttok(ep, &sz); + assert(start); + if (STRNEQ(start, sz, "}", 1)) + return(EQN_OK); + + EQN_MSG(MANDOCERR_EQNBADSCOPE, ep); + return(EQN_ERR); +} + +static enum eqn_rest +eqn_list(struct eqn_node *ep, struct eqn_box *last) +{ + struct eqn_box *bp; + const char *start; + size_t sz; + enum eqn_rest c; + + bp = eqn_box_alloc(ep, last); + bp->type = EQN_LIST; + + if (NULL == (start = eqn_nexttok(ep, &sz))) { + EQN_MSG(MANDOCERR_EQNEOF, ep); + return(EQN_ERR); + } + if ( ! STRNEQ(start, sz, "{", 1)) { + EQN_MSG(MANDOCERR_EQNSYNT, ep); + return(EQN_ERR); + } + + while (EQN_DESCOPE == (c = eqn_eqn(ep, bp))) { + eqn_rewind(ep); + start = eqn_nexttok(ep, &sz); + assert(start); + if ( ! STRNEQ(start, sz, "above", 5)) + break; + } + + if (EQN_DESCOPE != c) { + if (EQN_ERR != c) + EQN_MSG(MANDOCERR_EQNSCOPE, ep); + return(EQN_ERR); + } + + eqn_rewind(ep); + start = eqn_nexttok(ep, &sz); + assert(start); + if (STRNEQ(start, sz, "}", 1)) + return(EQN_OK); + + EQN_MSG(MANDOCERR_EQNBADSCOPE, ep); + return(EQN_ERR); +} + +static enum eqn_rest +eqn_box(struct eqn_node *ep, struct eqn_box *last) +{ + size_t sz; + const char *start; + char *left; + char sym[64]; + enum eqn_rest c; + int i, size; + struct eqn_box *bp; + + if (NULL == (start = eqn_nexttok(ep, &sz))) + return(EQN_EOF); + + if (STRNEQ(start, sz, "}", 1)) + return(EQN_DESCOPE); + else if (STRNEQ(start, sz, "right", 5)) + return(EQN_DESCOPE); + else if (STRNEQ(start, sz, "above", 5)) + return(EQN_DESCOPE); + else if (STRNEQ(start, sz, "mark", 4)) + return(EQN_OK); + else if (STRNEQ(start, sz, "lineup", 6)) + return(EQN_OK); + + for (i = 0; i < (int)EQN__MAX; i++) { + if ( ! EQNSTREQ(&eqnparts[i].str, start, sz)) + continue; + return((*eqnparts[i].fp)(ep) ? + EQN_OK : EQN_ERR); + } + + if (STRNEQ(start, sz, "{", 1)) { + if (EQN_DESCOPE != (c = eqn_eqn(ep, last))) { + if (EQN_ERR != c) + EQN_MSG(MANDOCERR_EQNSCOPE, ep); + return(EQN_ERR); + } + eqn_rewind(ep); + start = eqn_nexttok(ep, &sz); + assert(start); + if (STRNEQ(start, sz, "}", 1)) + return(EQN_OK); + EQN_MSG(MANDOCERR_EQNBADSCOPE, ep); + return(EQN_ERR); + } + + for (i = 0; i < (int)EQNPILE__MAX; i++) { + if ( ! EQNSTREQ(&eqnpiles[i], start, sz)) + continue; + if (EQN_OK == (c = eqn_list(ep, last))) + last->last->pile = (enum eqn_pilet)i; + return(c); + } + + if (STRNEQ(start, sz, "matrix", 6)) + return(eqn_matrix(ep, last)); + + if (STRNEQ(start, sz, "left", 4)) { + if (NULL == (start = eqn_nexttok(ep, &sz))) { + EQN_MSG(MANDOCERR_EQNEOF, ep); + return(EQN_ERR); + } + left = mandoc_strndup(start, sz); + c = eqn_eqn(ep, last); + if (last->last) + last->last->left = left; + else + free(left); + if (EQN_DESCOPE != c) + return(c); + assert(last->last); + eqn_rewind(ep); + start = eqn_nexttok(ep, &sz); + assert(start); + if ( ! STRNEQ(start, sz, "right", 5)) + return(EQN_DESCOPE); + if (NULL == (start = eqn_nexttok(ep, &sz))) { + EQN_MSG(MANDOCERR_EQNEOF, ep); + return(EQN_ERR); + } + last->last->right = mandoc_strndup(start, sz); + return(EQN_OK); + } + + for (i = 0; i < (int)EQNPOS__MAX; i++) { + if ( ! EQNSTREQ(&eqnposs[i], start, sz)) + continue; + if (NULL == last->last) { + EQN_MSG(MANDOCERR_EQNSYNT, ep); + return(EQN_ERR); + } + last->last->pos = (enum eqn_post)i; + if (EQN_EOF == (c = eqn_box(ep, last))) { + EQN_MSG(MANDOCERR_EQNEOF, ep); + return(EQN_ERR); + } + return(c); + } + + for (i = 0; i < (int)EQNMARK__MAX; i++) { + if ( ! EQNSTREQ(&eqnmarks[i], start, sz)) + continue; + if (NULL == last->last) { + EQN_MSG(MANDOCERR_EQNSYNT, ep); + return(EQN_ERR); + } + last->last->mark = (enum eqn_markt)i; + if (EQN_EOF == (c = eqn_box(ep, last))) { + EQN_MSG(MANDOCERR_EQNEOF, ep); + return(EQN_ERR); + } + return(c); + } + + for (i = 0; i < (int)EQNFONT__MAX; i++) { + if ( ! EQNSTREQ(&eqnfonts[i], start, sz)) + continue; + if (EQN_EOF == (c = eqn_box(ep, last))) { + EQN_MSG(MANDOCERR_EQNEOF, ep); + return(EQN_ERR); + } else if (EQN_OK == c) + last->last->font = (enum eqn_fontt)i; + return(c); + } + + if (STRNEQ(start, sz, "size", 4)) { + if (NULL == (start = eqn_nexttok(ep, &sz))) { + EQN_MSG(MANDOCERR_EQNEOF, ep); + return(EQN_ERR); + } + size = mandoc_strntoi(start, sz, 10); + if (EQN_EOF == (c = eqn_box(ep, last))) { + EQN_MSG(MANDOCERR_EQNEOF, ep); + return(EQN_ERR); + } else if (EQN_OK != c) + return(c); + last->last->size = size; + } + + bp = eqn_box_alloc(ep, last); + bp->type = EQN_TEXT; + for (i = 0; i < (int)EQNSYM__MAX; i++) + if (EQNSTREQ(&eqnsyms[i].str, start, sz)) { + sym[63] = '\0'; + snprintf(sym, 62, "\\[%s]", eqnsyms[i].sym); + bp->text = mandoc_strdup(sym); + return(EQN_OK); + } + + bp->text = mandoc_strndup(start, sz); + return(EQN_OK); +} + +void +eqn_free(struct eqn_node *p) +{ + int i; + + eqn_box_free(p->eqn.root); + + for (i = 0; i < (int)p->defsz; i++) { + free(p->defs[i].key); + free(p->defs[i].val); + } + + free(p->eqn.name); + free(p->data); + free(p->defs); + free(p); +} + +static struct eqn_box * +eqn_box_alloc(struct eqn_node *ep, struct eqn_box *parent) +{ + struct eqn_box *bp; + + bp = mandoc_calloc(1, sizeof(struct eqn_box)); + bp->parent = parent; + bp->size = ep->gsize; + + if (NULL == parent->first) + parent->first = bp; + else + parent->last->next = bp; + + parent->last = bp; + return(bp); +} + +static void +eqn_box_free(struct eqn_box *bp) +{ + + if (bp->first) + eqn_box_free(bp->first); + if (bp->next) + eqn_box_free(bp->next); + + free(bp->text); + free(bp->left); + free(bp->right); + free(bp); +} + +static const char * +eqn_nextrawtok(struct eqn_node *ep, size_t *sz) +{ + + return(eqn_next(ep, '"', sz, 0)); +} + +static const char * +eqn_nexttok(struct eqn_node *ep, size_t *sz) +{ + + return(eqn_next(ep, '"', sz, 1)); +} + +static void +eqn_rewind(struct eqn_node *ep) +{ + + ep->cur = ep->rew; +} + +static const char * +eqn_next(struct eqn_node *ep, char quote, size_t *sz, int repl) +{ + char *start, *next; + int q, diff, lim; + size_t ssz, dummy; + struct eqn_def *def; + + if (NULL == sz) + sz = &dummy; + + lim = 0; + ep->rew = ep->cur; +again: + /* Prevent self-definitions. */ + + if (lim >= EQN_NEST_MAX) { + EQN_MSG(MANDOCERR_ROFFLOOP, ep); + return(NULL); + } + + ep->cur = ep->rew; + start = &ep->data[(int)ep->cur]; + q = 0; + + if ('\0' == *start) + return(NULL); + + if (quote == *start) { + ep->cur++; + q = 1; + } + + start = &ep->data[(int)ep->cur]; + + if ( ! q) { + if ('{' == *start || '}' == *start) + ssz = 1; + else + ssz = strcspn(start + 1, " ^~\"{}\t") + 1; + next = start + (int)ssz; + if ('\0' == *next) + next = NULL; + } else + next = strchr(start, quote); + + if (NULL != next) { + *sz = (size_t)(next - start); + ep->cur += *sz; + if (q) + ep->cur++; + while (' ' == ep->data[(int)ep->cur] || + '\t' == ep->data[(int)ep->cur] || + '^' == ep->data[(int)ep->cur] || + '~' == ep->data[(int)ep->cur]) + ep->cur++; + } else { + if (q) + EQN_MSG(MANDOCERR_BADQUOTE, ep); + next = strchr(start, '\0'); + *sz = (size_t)(next - start); + ep->cur += *sz; + } + + /* Quotes aren't expanded for values. */ + + if (q || ! repl) + return(start); + + if (NULL != (def = eqn_def_find(ep, start, *sz))) { + diff = def->valsz - *sz; + + if (def->valsz > *sz) { + ep->sz += diff; + ep->data = mandoc_realloc(ep->data, ep->sz + 1); + ep->data[ep->sz] = '\0'; + start = &ep->data[(int)ep->rew]; + } + + diff = def->valsz - *sz; + memmove(start + *sz + diff, start + *sz, + (strlen(start) - *sz) + 1); + memcpy(start, def->val, def->valsz); + goto again; + } + + return(start); +} + +static int +eqn_do_ign1(struct eqn_node *ep) +{ + + if (NULL == eqn_nextrawtok(ep, NULL)) + EQN_MSG(MANDOCERR_EQNEOF, ep); + else + return(1); + + return(0); +} + +static int +eqn_do_ign2(struct eqn_node *ep) +{ + + if (NULL == eqn_nextrawtok(ep, NULL)) + EQN_MSG(MANDOCERR_EQNEOF, ep); + else if (NULL == eqn_nextrawtok(ep, NULL)) + EQN_MSG(MANDOCERR_EQNEOF, ep); + else + return(1); + + return(0); +} + +static int +eqn_do_tdefine(struct eqn_node *ep) +{ + + if (NULL == eqn_nextrawtok(ep, NULL)) + EQN_MSG(MANDOCERR_EQNEOF, ep); + else if (NULL == eqn_next(ep, ep->data[(int)ep->cur], NULL, 0)) + EQN_MSG(MANDOCERR_EQNEOF, ep); + else + return(1); + + return(0); +} + +static int +eqn_do_define(struct eqn_node *ep) +{ + const char *start; + size_t sz; + struct eqn_def *def; + int i; + + if (NULL == (start = eqn_nextrawtok(ep, &sz))) { + EQN_MSG(MANDOCERR_EQNEOF, ep); + return(0); + } + + /* + * Search for a key that already exists. + * Create a new key if none is found. + */ + + if (NULL == (def = eqn_def_find(ep, start, sz))) { + /* Find holes in string array. */ + for (i = 0; i < (int)ep->defsz; i++) + if (0 == ep->defs[i].keysz) + break; + + if (i == (int)ep->defsz) { + ep->defsz++; + ep->defs = mandoc_realloc + (ep->defs, ep->defsz * + sizeof(struct eqn_def)); + ep->defs[i].key = ep->defs[i].val = NULL; + } + + ep->defs[i].keysz = sz; + ep->defs[i].key = mandoc_realloc + (ep->defs[i].key, sz + 1); + + memcpy(ep->defs[i].key, start, sz); + ep->defs[i].key[(int)sz] = '\0'; + def = &ep->defs[i]; + } + + start = eqn_next(ep, ep->data[(int)ep->cur], &sz, 0); + + if (NULL == start) { + EQN_MSG(MANDOCERR_EQNEOF, ep); + return(0); + } + + def->valsz = sz; + def->val = mandoc_realloc(def->val, sz + 1); + memcpy(def->val, start, sz); + def->val[(int)sz] = '\0'; + return(1); +} + +static int +eqn_do_gfont(struct eqn_node *ep) +{ + + if (NULL == eqn_nextrawtok(ep, NULL)) { + EQN_MSG(MANDOCERR_EQNEOF, ep); + return(0); + } + return(1); +} + +static int +eqn_do_gsize(struct eqn_node *ep) +{ + const char *start; + size_t sz; + + if (NULL == (start = eqn_nextrawtok(ep, &sz))) { + EQN_MSG(MANDOCERR_EQNEOF, ep); + return(0); + } + ep->gsize = mandoc_strntoi(start, sz, 10); + return(1); +} + +static int +eqn_do_undef(struct eqn_node *ep) +{ + const char *start; + struct eqn_def *def; + size_t sz; + + if (NULL == (start = eqn_nextrawtok(ep, &sz))) { + EQN_MSG(MANDOCERR_EQNEOF, ep); + return(0); + } else if (NULL != (def = eqn_def_find(ep, start, sz))) + def->keysz = 0; + + return(1); +} + +static struct eqn_def * +eqn_def_find(struct eqn_node *ep, const char *key, size_t sz) +{ + int i; + + for (i = 0; i < (int)ep->defsz; i++) + if (ep->defs[i].keysz && STRNEQ(ep->defs[i].key, + ep->defs[i].keysz, key, sz)) + return(&ep->defs[i]); + + return(NULL); +} diff --git a/external/bsd/mdocml/dist/eqn_html.c b/external/bsd/mdocml/dist/eqn_html.c new file mode 100644 index 000000000..6f330c0d4 --- /dev/null +++ b/external/bsd/mdocml/dist/eqn_html.c @@ -0,0 +1,81 @@ +/* $Vendor-Id: eqn_html.c,v 1.2 2011/07/24 10:09:03 kristaps Exp $ */ +/* + * Copyright (c) 2011 Kristaps Dzonsons + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include + +#include "mandoc.h" +#include "out.h" +#include "html.h" + +static const enum htmltag fontmap[EQNFONT__MAX] = { + TAG_SPAN, /* EQNFONT_NONE */ + TAG_SPAN, /* EQNFONT_ROMAN */ + TAG_B, /* EQNFONT_BOLD */ + TAG_B, /* EQNFONT_FAT */ + TAG_I /* EQNFONT_ITALIC */ +}; + + +static void eqn_box(struct html *, const struct eqn_box *); + +void +print_eqn(struct html *p, const struct eqn *ep) +{ + struct htmlpair tag; + struct tag *t; + + PAIR_CLASS_INIT(&tag, "eqn"); + t = print_otag(p, TAG_SPAN, 1, &tag); + + p->flags |= HTML_NONOSPACE; + eqn_box(p, ep->root); + p->flags &= ~HTML_NONOSPACE; + + print_tagq(p, t); +} + +static void +eqn_box(struct html *p, const struct eqn_box *bp) +{ + struct tag *t; + + t = EQNFONT_NONE == bp->font ? NULL : + print_otag(p, fontmap[(int)bp->font], 0, NULL); + + if (bp->left) + print_text(p, bp->left); + + if (bp->text) + print_text(p, bp->text); + + if (bp->first) + eqn_box(p, bp->first); + + if (NULL != t) + print_tagq(p, t); + if (bp->right) + print_text(p, bp->right); + + if (bp->next) + eqn_box(p, bp->next); +} diff --git a/external/bsd/mdocml/dist/eqn_term.c b/external/bsd/mdocml/dist/eqn_term.c new file mode 100644 index 000000000..c214d7d69 --- /dev/null +++ b/external/bsd/mdocml/dist/eqn_term.c @@ -0,0 +1,76 @@ +/* $Vendor-Id: eqn_term.c,v 1.4 2011/07/24 10:09:03 kristaps Exp $ */ +/* + * Copyright (c) 2011 Kristaps Dzonsons + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include + +#include "mandoc.h" +#include "out.h" +#include "term.h" + +static const enum termfont fontmap[EQNFONT__MAX] = { + TERMFONT_NONE, /* EQNFONT_NONE */ + TERMFONT_NONE, /* EQNFONT_ROMAN */ + TERMFONT_BOLD, /* EQNFONT_BOLD */ + TERMFONT_BOLD, /* EQNFONT_FAT */ + TERMFONT_UNDER /* EQNFONT_ITALIC */ +}; + +static void eqn_box(struct termp *, const struct eqn_box *); + +void +term_eqn(struct termp *p, const struct eqn *ep) +{ + + p->flags |= TERMP_NONOSPACE; + eqn_box(p, ep->root); + term_word(p, " "); + p->flags &= ~TERMP_NONOSPACE; +} + +static void +eqn_box(struct termp *p, const struct eqn_box *bp) +{ + + if (EQNFONT_NONE != bp->font) + term_fontpush(p, fontmap[(int)bp->font]); + if (bp->left) + term_word(p, bp->left); + if (EQN_SUBEXPR == bp->type) + term_word(p, "("); + + if (bp->text) + term_word(p, bp->text); + + if (bp->first) + eqn_box(p, bp->first); + + if (EQN_SUBEXPR == bp->type) + term_word(p, ")"); + if (bp->right) + term_word(p, bp->right); + if (EQNFONT_NONE != bp->font) + term_fontpop(p); + + if (bp->next) + eqn_box(p, bp->next); +} diff --git a/external/bsd/mdocml/dist/example.style.css b/external/bsd/mdocml/dist/example.style.css index bdd1edf63..f45a34b61 100644 --- a/external/bsd/mdocml/dist/example.style.css +++ b/external/bsd/mdocml/dist/example.style.css @@ -1,146 +1,110 @@ -/* $Vendor-Id: example.style.css,v 1.41 2011/01/05 13:00:11 kristaps Exp $ */ - +/* $Vendor-Id: example.style.css,v 1.49 2011/12/15 12:18:57 kristaps Exp $ */ /* * This is an example style-sheet provided for mandoc(1) and the -Thtml * or -Txhtml output mode. - * - * It mimics the appearance of the traditional cvsweb output. - * + * It mimics the appearance of the legacy man.cgi output. * See mdoc(7) and man(7) for macro explanations. */ -html { min-width: 580px; width: 580px; } -body { font-family: monospace; } - -/* Preamble structure. */ - -table.foot { width: 100%; } /* Document footer. */ -td.foot-date { width: 50%; } /* Document footer: date. */ -td.foot-os { width: 50%; text-align: right; } /* Document footer: OS/source. */ -table.head { width: 100%; } /* Document header. */ -td.head-ltitle { width: 10%; } /* Document header: left-title. */ -td.head-vol { width: 80%; text-align: center; } /* Document header: volume. */ -td.head-rtitle { width: 10%; text-align: right; } /* Document header: right-title. */ - -/* Sections. */ - -h1 { margin-bottom: 0px; font-size: medium; margin-left: -4ex; } /* Section header (Sh, SH). */ -h2 { margin-bottom: 0px; font-size: medium; margin-left: -2ex; } /* Sub-section header (Ss, SS). */ -div.section { margin-bottom: 2ex; margin-left: 4ex; } /* Sections (Sh, SH). */ -div.subsection { } /* Sub-sections (Ss, SS). */ -table.synopsis { } /* SYNOPSIS section table. */ - -/* Vertical spacing. */ - -p { } /* Paragraph: Pp, Lp. */ -blockquote { margin-top: 0px; margin-bottom: 0px; } -table { margin-top: 0px; margin-bottom: 0px; } -td { vertical-align: top; } - -/* General font modes. */ - -i { } /* Italic: BI, IB, I, (implicit). */ -.emph { font-style: italic; font-weight: normal; } /* Emphasis: Em, Bl -emphasis. */ -b { } /* Bold: SB, BI, IB, BR, RB, B, (implicit). */ -.symb { font-style: normal; font-weight: bold; } /* Symbolic: Sy, Ms, Bf -symbolic. */ -small { } /* Small: SB, SM. */ - -/* Block modes. */ - -.display { } /* Top of all Bd, D1, Dl. */ -.list { } /* Top of all Bl. */ - -/* Context-specific modes. */ - -i.addr { font-weight: normal; } /* Address (Ad). */ -i.arg { font-weight: normal; } /* Command argument (Ar). */ -span.author { } /* Author name (An). */ -b.cmd { font-style: normal; } /* Command (Cm). */ -b.config { font-style: normal; } /* Config statement (Cd). */ -span.define { } /* Defines (Dv). */ -span.desc { } /* Nd. After em-dash. */ -b.diag { font-style: normal; } /* Diagnostic (Bl -diag). */ -span.env { } /* Environment variables (Ev). */ -span.errno { } /* Error string (Er). */ -i.farg { font-weight: normal; } /* Function argument (Fa, Fn). */ -i.file { font-weight: normal; } /* File (Pa). */ -b.flag { font-style: normal; } /* Flag (Fl, Cm). */ -b.fname { font-style: normal; } /* Function name (Fa, Fn, Rv). */ -i.ftype { font-weight: normal; } /* Function types (Ft, Fn). */ -b.includes { font-style: normal; } /* Header includes (In). */ -span.lib { } /* Library (Lb). */ -i.link-sec { font-weight: normal; } /* Section links (Sx). */ -code.lit { font-style: normal; font-weight: normal; } /* Literal: Dl, Li, Bf -literal, Bl -literal, Bl -unfilled. */ -b.macro { font-style: normal; } /* Macro-ish thing (Fd). */ -b.name { font-style: normal; } /* Name of utility (Nm). */ -span.opt { } /* Options (Op, Oo/Oc). */ -span.ref { } /* Citations (Rs). */ -span.ref-auth { } /* Reference author (%A). */ -i.ref-book { font-weight: normal; } /* Reference book (%B). */ -span.ref-city { } /* Reference city (%C). */ -span.ref-date { } /* Reference date (%D). */ -i.ref-issue { font-weight: normal; } /* Reference issuer/publisher (%I). */ -i.ref-jrnl { font-weight: normal; } /* Reference journal (%J). */ -span.ref-num { } /* Reference number (%N). */ -span.ref-opt { } /* Reference optionals (%O). */ -span.ref-page { } /* Reference page (%P). */ -span.ref-corp { } /* Reference corporate/foreign author (%Q). */ -span.ref-rep { } /* Reference report (%R). */ -span.ref-title { text-decoration: underline; } /* Reference title (%T). */ -span.ref-vol { } /* Reference volume (%V). */ -span.type { font-style: italic; font-weight: normal; } /* Variable types (Vt). */ -span.unix { } /* Unices (Ux, Ox, Nx, Fx, Bx, Bsx, Dx). */ -b.utility { font-style: normal; } /* Name of utility (Ex). */ -b.var { font-style: normal; } /* Variables (Rv). */ - -a.link-ext { } /* Off-site link (Lk). */ -a.link-includes { } /* Include-file link (In). */ -a.link-mail { } /* Mailto links (Mt). */ -a.link-man { } /* Manual links (Xr). */ -a.link-ref { } /* Reference section links (%Q). */ -a.link-sec { } /* Section links (Sx). */ - -/* Formatting for lists. See mdoc(7). */ - -dl.list-diag { } -dt.list-diag { } -dd.list-diag { } - -dl.list-hang { } -dt.list-hang { } -dd.list-hang { } - -dl.list-inset { } -dt.list-inset { } -dd.list-inset { } - -dl.list-ohang { } -dt.list-ohang { } -dd.list-ohang { margin-left: 0em; } - -dl.list-tag { } -dt.list-tag { } -dd.list-tag { } - -table.list-col { } -tr.list-col { } -td.list-col { } - -ul.list-bul { list-style-type: disc; padding-left: 1em; } -li.list-bul { } - -ul.list-dash { list-style-type: none; padding-left: 0em; } -li.list-dash:before { content: "\2014 "; } - -ul.list-hyph { list-style-type: none; padding-left: 0em; } -li.list-hyph:before { content: "\2013 "; } - -ul.list-item { list-style-type: none; padding-left: 0em; } -li.list-item { } - -ol.list-enum { padding-left: 2em; } -li.list-enum { } - -/* Table modes. See tbl(7). */ - -table.tbl { } +div.mandoc { min-width: 102ex; + width: 102ex; + font-family: monospace; } /* This is the outer node of all mandoc -T[x]html documents. */ +div.mandoc h1 { margin-bottom: 0ex; font-size: inherit; margin-left: -4ex; } /* Section header (Sh, SH). */ +div.mandoc h2 { margin-bottom: 0ex; font-size: inherit; margin-left: -2ex; } /* Sub-section header (Ss, SS). */ +div.mandoc table { width: 100%; margin-top: 0ex; margin-bottom: 0ex; } /* All tables. */ +div.mandoc td { vertical-align: top; } /* All table cells. */ +div.mandoc p { } /* Paragraph: Pp, Lp. */ +div.mandoc blockquote { margin-left: 5ex; margin-top: 0ex; margin-bottom: 0ex; } /* D1, Dl. */ +div.mandoc div.section { margin-bottom: 2ex; margin-left: 5ex; } /* Sections (Sh, SH). */ +div.mandoc div.subsection { } /* Sub-sections (Ss, SS). */ +div.mandoc table.synopsis { } /* SYNOPSIS section table. */ +div.mandoc table.foot { } /* Document footer. */ +div.mandoc td.foot-date { width: 50%; } /* Document footer: date. */ +div.mandoc td.foot-os { width: 50%; text-align: right; } /* Document footer: OS/source. */ +div.mandoc table.head { } /* Document header. */ +div.mandoc td.head-ltitle { width: 10%; } /* Document header: left-title. */ +div.mandoc td.head-vol { width: 80%; text-align: center; } /* Document header: volume. */ +div.mandoc td.head-rtitle { width: 10%; text-align: right; } /* Document header: right-title. */ +div.mandoc .display { } /* All Bd, D1, Dl. */ +div.mandoc .list { } /* All Bl. */ +div.mandoc i { } /* Italic: BI, IB, I, (implicit). */ +div.mandoc b { } /* Bold: SB, BI, IB, BR, RB, B, (implicit). */ +div.mandoc small { } /* Small: SB, SM. */ +div.mandoc .emph { font-style: italic; font-weight: normal; } /* Emphasis: Em, Bl -emphasis. */ +div.mandoc .symb { font-style: normal; font-weight: bold; } /* Symbolic: Sy, Ms, Bf -symbolic. */ +div.mandoc .lit { font-style: normal; font-weight: normal; font-family: monospace; } /* Literal: Dl, Li, Ql, Bf -literal, Bl -literal, Bl -unfilled. */ +div.mandoc i.addr { font-weight: normal; } /* Address (Ad). */ +div.mandoc i.arg { font-weight: normal; } /* Command argument (Ar). */ +div.mandoc span.author { } /* Author name (An). */ +div.mandoc b.cmd { font-style: normal; } /* Command (Cm). */ +div.mandoc b.config { font-style: normal; } /* Config statement (Cd). */ +div.mandoc span.define { } /* Defines (Dv). */ +div.mandoc span.desc { } /* Nd. After em-dash. */ +div.mandoc b.diag { font-style: normal; } /* Diagnostic (Bl -diag). */ +div.mandoc span.env { } /* Environment variables (Ev). */ +div.mandoc span.errno { } /* Error string (Er). */ +div.mandoc i.farg { font-weight: normal; } /* Function argument (Fa, Fn). */ +div.mandoc i.file { font-weight: normal; } /* File (Pa). */ +div.mandoc b.flag { font-style: normal; } /* Flag (Fl, Cm). */ +div.mandoc b.fname { font-style: normal; } /* Function name (Fa, Fn, Rv). */ +div.mandoc i.ftype { font-weight: normal; } /* Function types (Ft, Fn). */ +div.mandoc b.includes { font-style: normal; } /* Header includes (In). */ +div.mandoc span.lib { } /* Library (Lb). */ +div.mandoc i.link-sec { font-weight: normal; } /* Section links (Sx). */ +div.mandoc b.macro { font-style: normal; } /* Macro-ish thing (Fd). */ +div.mandoc b.name { font-style: normal; } /* Name of utility (Nm). */ +div.mandoc span.opt { } /* Options (Op, Oo/Oc). */ +div.mandoc span.ref { } /* Citations (Rs). */ +div.mandoc span.ref-auth { } /* Reference author (%A). */ +div.mandoc i.ref-book { font-weight: normal; } /* Reference book (%B). */ +div.mandoc span.ref-city { } /* Reference city (%C). */ +div.mandoc span.ref-date { } /* Reference date (%D). */ +div.mandoc i.ref-issue { font-weight: normal; } /* Reference issuer/publisher (%I). */ +div.mandoc i.ref-jrnl { font-weight: normal; } /* Reference journal (%J). */ +div.mandoc span.ref-num { } /* Reference number (%N). */ +div.mandoc span.ref-opt { } /* Reference optionals (%O). */ +div.mandoc span.ref-page { } /* Reference page (%P). */ +div.mandoc span.ref-corp { } /* Reference corporate/foreign author (%Q). */ +div.mandoc span.ref-rep { } /* Reference report (%R). */ +div.mandoc span.ref-title { text-decoration: underline; } /* Reference title (%T). */ +div.mandoc span.ref-vol { } /* Reference volume (%V). */ +div.mandoc span.type { font-style: italic; font-weight: normal; } /* Variable types (Vt). */ +div.mandoc span.unix { } /* Unices (Ux, Ox, Nx, Fx, Bx, Bsx, Dx). */ +div.mandoc b.utility { font-style: normal; } /* Name of utility (Ex). */ +div.mandoc b.var { font-style: normal; } /* Variables (Rv). */ +div.mandoc a.link-ext { } /* Off-site link (Lk). */ +div.mandoc a.link-includes { } /* Include-file link (In). */ +div.mandoc a.link-mail { } /* Mailto links (Mt). */ +div.mandoc a.link-man { } /* Manual links (Xr). */ +div.mandoc a.link-ref { } /* Reference section links (%Q). */ +div.mandoc a.link-sec { } /* Section links (Sx). */ +div.mandoc dl.list-diag { } /* Formatting for lists. See mdoc(7). */ +div.mandoc dt.list-diag { } +div.mandoc dd.list-diag { } +div.mandoc dl.list-hang { } +div.mandoc dt.list-hang { } +div.mandoc dd.list-hang { } +div.mandoc dl.list-inset { } +div.mandoc dt.list-inset { } +div.mandoc dd.list-inset { } +div.mandoc dl.list-ohang { } +div.mandoc dt.list-ohang { } +div.mandoc dd.list-ohang { margin-left: 0ex; } +div.mandoc dl.list-tag { } +div.mandoc dt.list-tag { } +div.mandoc dd.list-tag { } +div.mandoc table.list-col { } +div.mandoc tr.list-col { } +div.mandoc td.list-col { } +div.mandoc ul.list-bul { list-style-type: disc; padding-left: 1em; } +div.mandoc li.list-bul { } +div.mandoc ul.list-dash { list-style-type: none; padding-left: 0em; } +div.mandoc li.list-dash:before { content: "\2014 "; } +div.mandoc ul.list-hyph { list-style-type: none; padding-left: 0em; } +div.mandoc li.list-hyph:before { content: "\2013 "; } +div.mandoc ul.list-item { list-style-type: none; padding-left: 0em; } +div.mandoc li.list-item { } +div.mandoc ol.list-enum { padding-left: 2em; } +div.mandoc li.list-enum { } +div.mandoc span.eqn { } /* Equation modes. See eqn(7). */ +div.mandoc table.tbl { } /* Table modes. See tbl(7). */ diff --git a/external/bsd/mdocml/dist/external.png.uu b/external/bsd/mdocml/dist/external.png.uu index 6e651bcc9..9f71912ff 100644 --- a/external/bsd/mdocml/dist/external.png.uu +++ b/external/bsd/mdocml/dist/external.png.uu @@ -1,4 +1,4 @@ -begin 644 external.png +begin 664 external.png MB5!.1PT*&@H````-24A$4@````H````*"`,```"Z[#^/````%5!,5$5FFRR#IR])3+$:.A0J[. diff --git a/external/bsd/mdocml/dist/html.c b/external/bsd/mdocml/dist/html.c index f02a80846..9c016bab8 100644 --- a/external/bsd/mdocml/dist/html.c +++ b/external/bsd/mdocml/dist/html.c @@ -1,6 +1,7 @@ -/* $Vendor-Id: html.c,v 1.124 2010/12/27 21:41:05 schwarze Exp $ */ +/* $Vendor-Id: html.c,v 1.150 2011/10/05 21:35:17 kristaps Exp $ */ /* - * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons + * Copyright (c) 2011 Ingo Schwarze * * 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 +31,8 @@ #include #include "mandoc.h" +#include "libmandoc.h" #include "out.h" -#include "chars.h" #include "html.h" #include "main.h" @@ -90,42 +91,47 @@ static const char *const htmlattrs[ATTR_MAX] = { "id", /* ATTR_ID */ "summary", /* ATTR_SUMMARY */ "align", /* ATTR_ALIGN */ + "colspan", /* ATTR_COLSPAN */ }; -static void print_spec(struct html *, enum roffdeco, - const char *, size_t); -static void print_res(struct html *, const char *, size_t); -static void print_ctag(struct html *, enum htmltag); -static void print_doctype(struct html *); -static void print_xmltype(struct html *); -static int print_encode(struct html *, const char *, int); -static void print_metaf(struct html *, enum roffdeco); -static void print_attr(struct html *, - const char *, const char *); -static void *ml_alloc(char *, enum htmltype); +static const char *const roffscales[SCALE_MAX] = { + "cm", /* SCALE_CM */ + "in", /* SCALE_IN */ + "pc", /* SCALE_PC */ + "pt", /* SCALE_PT */ + "em", /* SCALE_EM */ + "em", /* SCALE_MM */ + "ex", /* SCALE_EN */ + "ex", /* SCALE_BU */ + "em", /* SCALE_VS */ + "ex", /* SCALE_FS */ +}; +static void bufncat(struct html *, const char *, size_t); +static void print_ctag(struct html *, enum htmltag); +static int print_encode(struct html *, const char *, int); +static void print_metaf(struct html *, enum mandoc_esc); +static void print_attr(struct html *, const char *, const char *); +static void *ml_alloc(char *, enum htmltype); static void * ml_alloc(char *outopts, enum htmltype type) { struct html *h; - const char *toks[4]; + const char *toks[5]; char *v; toks[0] = "style"; toks[1] = "man"; toks[2] = "includes"; - toks[3] = NULL; + toks[3] = "fragment"; + toks[4] = NULL; - h = calloc(1, sizeof(struct html)); - if (NULL == h) { - perror(NULL); - exit((int)MANDOCLEVEL_SYSERR); - } + h = mandoc_calloc(1, sizeof(struct html)); h->type = type; h->tags.head = NULL; - h->symtab = chars_init(CHARS_HTML); + h->symtab = mchars_alloc(); while (outopts && *outopts) switch (getsubopt(&outopts, UNCONST(toks), &v)) { @@ -138,6 +144,9 @@ ml_alloc(char *outopts, enum htmltype type) case (2): h->base_includes = v; break; + case (3): + h->oflags |= HTML_FRAGMENT; + break; default: break; } @@ -175,7 +184,7 @@ html_free(void *p) } if (h->symtab) - chars_free(h->symtab); + mchars_free(h->symtab); free(h); } @@ -211,62 +220,24 @@ print_gen_head(struct html *h) } } - static void -print_spec(struct html *h, enum roffdeco d, const char *p, size_t len) -{ - int cp; - const char *rhs; - size_t sz; - - if ((cp = chars_spec2cp(h->symtab, p, len)) > 0) { - printf("&#%d;", cp); - return; - } else if (-1 == cp && DECO_SSPECIAL == d) { - fwrite(p, 1, len, stdout); - return; - } else if (-1 == cp) - return; - - if (NULL != (rhs = chars_spec2str(h->symtab, p, len, &sz))) - fwrite(rhs, 1, sz, stdout); -} - - -static void -print_res(struct html *h, const char *p, size_t len) -{ - int cp; - const char *rhs; - size_t sz; - - if ((cp = chars_res2cp(h->symtab, p, len)) > 0) { - printf("&#%d;", cp); - return; - } else if (-1 == cp) - return; - - if (NULL != (rhs = chars_res2str(h->symtab, p, len, &sz))) - fwrite(rhs, 1, sz, stdout); -} - - -static void -print_metaf(struct html *h, enum roffdeco deco) +print_metaf(struct html *h, enum mandoc_esc deco) { enum htmlfont font; switch (deco) { - case (DECO_PREVIOUS): + case (ESCAPE_FONTPREV): font = h->metal; break; - case (DECO_ITALIC): + case (ESCAPE_FONTITALIC): font = HTMLFONT_ITALIC; break; - case (DECO_BOLD): + case (ESCAPE_FONTBOLD): font = HTMLFONT_BOLD; break; - case (DECO_ROMAN): + case (ESCAPE_FONT): + /* FALLTHROUGH */ + case (ESCAPE_FONTROMAN): font = HTMLFONT_NONE; break; default: @@ -288,77 +259,123 @@ print_metaf(struct html *h, enum roffdeco deco) print_otag(h, TAG_I, 0, NULL); } +int +html_strlen(const char *cp) +{ + int ssz, sz; + const char *seq, *p; + + /* + * Account for escaped sequences within string length + * calculations. This follows the logic in term_strlen() as we + * must calculate the width of produced strings. + * Assume that characters are always width of "1". This is + * hacky, but it gets the job done for approximation of widths. + */ + + sz = 0; + while (NULL != (p = strchr(cp, '\\'))) { + sz += (int)(p - cp); + ++cp; + switch (mandoc_escape(&cp, &seq, &ssz)) { + case (ESCAPE_ERROR): + return(sz); + case (ESCAPE_UNICODE): + /* FALLTHROUGH */ + case (ESCAPE_NUMBERED): + /* FALLTHROUGH */ + case (ESCAPE_SPECIAL): + sz++; + break; + default: + break; + } + } + + assert(sz >= 0); + return(sz + strlen(cp)); +} static int print_encode(struct html *h, const char *p, int norecurse) { size_t sz; - int len, nospace; + int c, len, nospace; const char *seq; - enum roffdeco deco; + enum mandoc_esc esc; static const char rejs[6] = { '\\', '<', '>', '&', ASCII_HYPH, '\0' }; nospace = 0; - for (; *p; p++) { + while ('\0' != *p) { sz = strcspn(p, rejs); fwrite(p, 1, sz, stdout); - p += /* LINTED */ - sz; + p += (int)sz; - if ('<' == *p) { + if ('\0' == *p) + break; + + switch (*p++) { + case ('<'): printf("<"); continue; - } else if ('>' == *p) { + case ('>'): printf(">"); continue; - } else if ('&' == *p) { + case ('&'): printf("&"); continue; - } else if (ASCII_HYPH == *p) { - /* - * Note: "soft hyphens" aren't graphically - * displayed when not breaking the text; we want - * them to be displayed. - */ - /*printf("­");*/ + case (ASCII_HYPH): putchar('-'); continue; - } else if ('\0' == *p) - break; - - seq = ++p; - len = a2roffdeco(&deco, &seq, &sz); - - switch (deco) { - case (DECO_RESERVED): - print_res(h, seq, sz); - break; - case (DECO_SSPECIAL): - /* FALLTHROUGH */ - case (DECO_SPECIAL): - print_spec(h, deco, seq, sz); - break; - case (DECO_PREVIOUS): - /* FALLTHROUGH */ - case (DECO_BOLD): - /* FALLTHROUGH */ - case (DECO_ITALIC): - /* FALLTHROUGH */ - case (DECO_ROMAN): - if (norecurse) - break; - print_metaf(h, deco); - break; default: break; } - p += len - 1; + esc = mandoc_escape(&p, &seq, &len); + if (ESCAPE_ERROR == esc) + break; - if (DECO_NOSPACE == deco && '\0' == *(p + 1)) - nospace = 1; + switch (esc) { + case (ESCAPE_UNICODE): + /* Skip passed "u" header. */ + c = mchars_num2uc(seq + 1, len - 1); + if ('\0' != c) + printf("&#x%x;", c); + break; + case (ESCAPE_NUMBERED): + c = mchars_num2char(seq, len); + if ('\0' != c) + putchar(c); + break; + case (ESCAPE_SPECIAL): + c = mchars_spec2cp(h->symtab, seq, len); + if (c > 0) + printf("&#%d;", c); + else if (-1 == c && 1 == len) + putchar((int)*seq); + break; + case (ESCAPE_FONT): + /* FALLTHROUGH */ + case (ESCAPE_FONTPREV): + /* FALLTHROUGH */ + case (ESCAPE_FONTBOLD): + /* FALLTHROUGH */ + case (ESCAPE_FONTITALIC): + /* FALLTHROUGH */ + case (ESCAPE_FONTROMAN): + if (norecurse) + break; + print_metaf(h, esc); + break; + case (ESCAPE_NOSPACE): + if ('\0' == *p) + nospace = 1; + break; + default: + break; + } } return(nospace); @@ -384,11 +401,7 @@ print_otag(struct html *h, enum htmltag tag, /* Push this tags onto the stack of open scopes. */ if ( ! (HTML_NOSTACK & htmltags[tag].flags)) { - t = malloc(sizeof(struct tag)); - if (NULL == t) { - perror(NULL); - exit((int)MANDOCLEVEL_SYSERR); - } + t = mandoc_malloc(sizeof(struct tag)); t->tag = tag; t->next = h->tags.head; h->tags.head = t; @@ -425,7 +438,7 @@ print_otag(struct html *h, enum htmltag tag, print_attr(h, "lang", "en"); } - /* Accomodate for XML "well-formed" singleton escaping. */ + /* Accommodate for XML "well-formed" singleton escaping. */ if (HTML_AUTOCLOSE & htmltags[tag].flags) switch (h->type) { @@ -458,27 +471,8 @@ print_ctag(struct html *h, enum htmltag tag) } } - void print_gen_decls(struct html *h) -{ - - print_xmltype(h); - print_doctype(h); -} - - -static void -print_xmltype(struct html *h) -{ - - if (HTML_XHTML_1_0_STRICT == h->type) - puts(""); -} - - -static void -print_doctype(struct html *h) { const char *doctype; const char *dtd; @@ -491,6 +485,7 @@ print_doctype(struct html *h) dtd = "http://www.w3.org/TR/html4/strict.dtd"; break; default: + puts(""); name = "html"; doctype = "-//W3C//DTD XHTML 1.0 Strict//EN"; dtd = "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"; @@ -501,35 +496,10 @@ print_doctype(struct html *h) name, doctype, dtd); } - void print_text(struct html *h, const char *word) { - if (word[0] && '\0' == word[1]) - switch (word[0]) { - case('.'): - /* FALLTHROUGH */ - case(','): - /* FALLTHROUGH */ - case(';'): - /* FALLTHROUGH */ - case(':'): - /* FALLTHROUGH */ - case('?'): - /* FALLTHROUGH */ - case('!'): - /* FALLTHROUGH */ - case(')'): - /* FALLTHROUGH */ - case(']'): - if ( ! (HTML_IGNDELIM & h->flags)) - h->flags |= HTML_NOSPACE; - break; - default: - break; - } - if ( ! (HTML_NOSPACE & h->flags)) { /* Manage keeps! */ if ( ! (HTML_KEEP & h->flags)) { @@ -547,9 +517,11 @@ print_text(struct html *h, const char *word) print_otag(h, TAG_I, 0, NULL); assert(word); - if ( ! print_encode(h, word, 0)) + if ( ! print_encode(h, word, 0)) { if ( ! (h->flags & HTML_NONOSPACE)) h->flags &= ~HTML_NOSPACE; + } else + h->flags |= HTML_NOSPACE; if (h->metaf) { print_tagq(h, h->metaf); @@ -557,21 +529,6 @@ print_text(struct html *h, const char *word) } h->flags &= ~HTML_IGNDELIM; - - /* - * Note that we don't process the pipe: the parser sees it as - * punctuation, but we don't in terms of typography. - */ - if (word[0] && '\0' == word[1]) - switch (word[0]) { - case('('): - /* FALLTHROUGH */ - case('['): - h->flags |= HTML_NOSPACE; - break; - default: - break; - } } @@ -581,8 +538,14 @@ print_tagq(struct html *h, const struct tag *until) struct tag *tag; while ((tag = h->tags.head) != NULL) { + /* + * Remember to close out and nullify the current + * meta-font and table, if applicable. + */ if (tag == h->metaf) h->metaf = NULL; + if (tag == h->tblt) + h->tblt = NULL; print_ctag(h, tag->tag); h->tags.head = tag->next; free(tag); @@ -600,15 +563,20 @@ print_stagq(struct html *h, const struct tag *suntil) while ((tag = h->tags.head) != NULL) { if (suntil && tag == suntil) return; + /* + * Remember to close out and nullify the current + * meta-font and table, if applicable. + */ if (tag == h->metaf) h->metaf = NULL; + if (tag == h->tblt) + h->tblt = NULL; print_ctag(h, tag->tag); h->tags.head = tag->next; free(tag); } } - void bufinit(struct html *h) { @@ -617,28 +585,26 @@ bufinit(struct html *h) h->buflen = 0; } - void bufcat_style(struct html *h, const char *key, const char *val) { bufcat(h, key); - bufncat(h, ":", 1); + bufcat(h, ":"); bufcat(h, val); - bufncat(h, ";", 1); + bufcat(h, ";"); } - void bufcat(struct html *h, const char *p) { - bufncat(h, p, strlen(p)); + h->buflen = strlcat(h->buf, p, BUFSIZ); + assert(h->buflen < BUFSIZ); } - void -buffmt(struct html *h, const char *fmt, ...) +bufcat_fmt(struct html *h, const char *fmt, ...) { va_list ap; @@ -649,19 +615,15 @@ buffmt(struct html *h, const char *fmt, ...) h->buflen = strlen(h->buf); } - -void +static void bufncat(struct html *h, const char *p, size_t sz) { - if (h->buflen + sz > BUFSIZ - 1) - sz = BUFSIZ - 1 - h->buflen; - - (void)strncat(h->buf, p, sz); + assert(h->buflen + sz + 1 < BUFSIZ); + strncat(h->buf, p, sz); h->buflen += sz; } - void buffmt_includes(struct html *h, const char *name) { @@ -669,6 +631,7 @@ buffmt_includes(struct html *h, const char *name) pp = h->base_includes; + bufinit(h); while (NULL != (p = strchr(pp, '%'))) { bufncat(h, pp, (size_t)(p - pp)); switch (*(p + 1)) { @@ -685,7 +648,6 @@ buffmt_includes(struct html *h, const char *name) bufcat(h, pp); } - void buffmt_man(struct html *h, const char *name, const char *sec) @@ -694,7 +656,7 @@ buffmt_man(struct html *h, pp = h->base_man; - /* LINTED */ + bufinit(h); while (NULL != (p = strchr(pp, '%'))) { bufncat(h, pp, (size_t)(p - pp)); switch (*(p + 1)) { @@ -702,7 +664,7 @@ buffmt_man(struct html *h, bufcat(h, sec ? sec : "1"); break; case('N'): - buffmt(h, name); + bufcat_fmt(h, name); break; default: bufncat(h, p, 2); @@ -714,85 +676,24 @@ buffmt_man(struct html *h, bufcat(h, pp); } - void bufcat_su(struct html *h, const char *p, const struct roffsu *su) { double v; - const char *u; v = su->scale; + if (SCALE_MM == su->unit && 0.0 == (v /= 100.0)) + v = 1.0; - switch (su->unit) { - case (SCALE_CM): - u = "cm"; - break; - case (SCALE_IN): - u = "in"; - break; - case (SCALE_PC): - u = "pc"; - break; - case (SCALE_PT): - u = "pt"; - break; - case (SCALE_EM): - u = "em"; - break; - case (SCALE_MM): - if (0 == (v /= 100)) - v = 1; - u = "em"; - break; - case (SCALE_EN): - u = "ex"; - break; - case (SCALE_BU): - u = "ex"; - break; - case (SCALE_VS): - u = "em"; - break; - default: - u = "ex"; - break; - } - - /* - * XXX: the CSS spec isn't clear as to which types accept - * integer or real numbers, so we just make them all decimals. - */ - buffmt(h, "%s: %.2f%s;", p, v, u); + bufcat_fmt(h, "%s: %.2f%s;", p, v, roffscales[su->unit]); } - void -html_idcat(char *dst, const char *src, int sz) +bufcat_id(struct html *h, const char *src) { - int ssz; - - assert(sz > 2); /* Cf. . */ - /* We can't start with a number (bah). */ - - if ('#' == *dst) { - dst++; - sz--; - } - if ('\0' == *dst) { - *dst++ = 'x'; - *dst = '\0'; - sz--; - } - - for ( ; *dst != '\0' && sz; dst++, sz--) - /* Jump to end. */ ; - - for ( ; *src != '\0' && sz > 1; src++) { - ssz = snprintf(dst, (size_t)sz, "%.2x", *src); - sz -= ssz; - dst += ssz; - } + while ('\0' != *src) + bufcat_fmt(h, "%.2x", *src++); } diff --git a/external/bsd/mdocml/dist/html.h b/external/bsd/mdocml/dist/html.h index 65e35946b..4cbe29349 100644 --- a/external/bsd/mdocml/dist/html.h +++ b/external/bsd/mdocml/dist/html.h @@ -1,6 +1,6 @@ -/* $Vendor-Id: html.h,v 1.38 2011/01/06 11:55:39 kristaps Exp $ */ +/* $Vendor-Id: html.h,v 1.47 2011/10/05 21:35:17 kristaps Exp $ */ /* - * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons * * 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,7 @@ enum htmlattr { ATTR_ID, ATTR_SUMMARY, ATTR_ALIGN, + ATTR_COLSPAN, ATTR_MAX }; @@ -103,30 +104,34 @@ struct htmlpair { #define PAIR_STYLE_INIT(p, h) PAIR_INIT(p, ATTR_STYLE, (h)->buf) #define PAIR_SUMMARY_INIT(p, v) PAIR_INIT(p, ATTR_SUMMARY, v) -enum htmltype { +enum htmltype { HTML_HTML_4_01_STRICT, HTML_XHTML_1_0_STRICT }; struct html { int flags; -#define HTML_NOSPACE (1 << 0) +#define HTML_NOSPACE (1 << 0) /* suppress next space */ #define HTML_IGNDELIM (1 << 1) #define HTML_KEEP (1 << 2) #define HTML_PREKEEP (1 << 3) -#define HTML_NONOSPACE (1 << 4) +#define HTML_NONOSPACE (1 << 4) /* never add spaces */ +#define HTML_LITERAL (1 << 5) /* literal (e.g.,
) context */
 	struct tagq	  tags; /* stack of open tags */
 	struct rofftbl	  tbl; /* current table */
-	void		 *symtab; /* character-escapes */
+	struct tag	 *tblt; /* current open table scope */
+	struct mchars	 *symtab; /* character-escapes */
 	char		 *base_man; /* base for manpage href */
 	char		 *base_includes; /* base for include href */
 	char		 *style; /* style-sheet URI */
 	char		  buf[BUFSIZ]; /* see bufcat and friends */
-	size_t		  buflen;
+	size_t		  buflen; 
 	struct tag	 *metaf; /* current open font scope */
 	enum htmlfont	  metal; /* last used font */
 	enum htmlfont	  metac; /* current font mode */
-	enum htmltype	  type;
+	enum htmltype	  type; /* output media type */
+	int		  oflags; /* output options */
+#define	HTML_FRAGMENT	 (1 << 0) /* don't emit HTML/HEAD/BODY */
 };
 
 void		  print_gen_decls(struct html *);
@@ -136,21 +141,23 @@ struct tag	 *print_otag(struct html *, enum htmltag,
 void		  print_tagq(struct html *, const struct tag *);
 void		  print_stagq(struct html *, const struct tag *);
 void		  print_text(struct html *, const char *);
+void		  print_tblclose(struct html *);
 void		  print_tbl(struct html *, const struct tbl_span *);
+void		  print_eqn(struct html *, const struct eqn *);
 
+void		  bufcat_fmt(struct html *, const char *, ...);
+void		  bufcat(struct html *, const char *);
+void		  bufcat_id(struct html *, const char *);
+void		  bufcat_style(struct html *, 
+			const char *, const char *);
 void		  bufcat_su(struct html *, const char *, 
 			const struct roffsu *);
+void		  bufinit(struct html *);
 void		  buffmt_man(struct html *, 
 			const char *, const char *);
 void		  buffmt_includes(struct html *, const char *);
-void		  buffmt(struct html *, const char *, ...);
-void		  bufcat(struct html *, const char *);
-void		  bufcat_style(struct html *, 
-			const char *, const char *);
-void		  bufncat(struct html *, const char *, size_t);
-void		  bufinit(struct html *);
 
-void		  html_idcat(char *, const char *, int);
+int		  html_strlen(const char *);
 
 __END_DECLS
 
diff --git a/external/bsd/mdocml/dist/lib.c b/external/bsd/mdocml/dist/lib.c
index 85094818f..7c239076d 100644
--- a/external/bsd/mdocml/dist/lib.c
+++ b/external/bsd/mdocml/dist/lib.c
@@ -1,4 +1,4 @@
-/*	$Vendor-Id: lib.c,v 1.8 2010/06/19 20:46:27 kristaps Exp $ */
+/*	$Vendor-Id: lib.c,v 1.9 2011/03/22 14:33:05 kristaps Exp $ */
 /*
  * Copyright (c) 2009 Kristaps Dzonsons 
  *
@@ -22,6 +22,7 @@
 #include 
 #include 
 
+#include "mdoc.h"
 #include "mandoc.h"
 #include "libmdoc.h"
 
diff --git a/external/bsd/mdocml/dist/lib.in b/external/bsd/mdocml/dist/lib.in
index 6d2788959..ef6352df9 100644
--- a/external/bsd/mdocml/dist/lib.in
+++ b/external/bsd/mdocml/dist/lib.in
@@ -1,4 +1,4 @@
-/*	$Vendor-Id: lib.in,v 1.9 2010/06/19 20:46:27 kristaps Exp $ */
+/*	$Vendor-Id: lib.in,v 1.13 2012/01/28 23:46:28 joerg Exp $ */
 /*
  * Copyright (c) 2009 Kristaps Dzonsons 
  *
@@ -40,9 +40,11 @@ LINE("libcurses",	"Curses Library (libcurses, \\-lcurses)")
 LINE("libdevinfo",	"Device and Resource Information Utility Library (libdevinfo, \\-ldevinfo)")
 LINE("libdevstat",	"Device Statistics Library (libdevstat, \\-ldevstat)")
 LINE("libdisk",		"Interface to Slice and Partition Labels Library (libdisk, \\-ldisk)")
+LINE("libdwarf",	"DWARF Access Library (libdwarf, \\-ldwarf)")
 LINE("libedit",		"Command Line Editor Library (libedit, \\-ledit)")
-LINE("libelf",		"ELF Parsing Library (libelf, \\-lelf)")
+LINE("libelf",		"ELF Access Library (libelf, \\-lelf)")
 LINE("libevent",	"Event Notification Library (libevent, \\-levent)")
+LINE("libexecinfo",	"Backtrace Information Library (libexecinfo, \\-lexecinfo)")
 LINE("libfetch",	"File Transfer Library for URLs (libfetch, \\-lfetch)")
 LINE("libform",		"Curses Form Library (libform, \\-lform)")
 LINE("libgeom",		"Userland API Library for kernel GEOM subsystem (libgeom, \\-lgeom)")
@@ -71,16 +73,20 @@ LINE("libpcap",		"Capture Library (libpcap, \\-lpcap)")
 LINE("libpci",		"PCI Bus Access Library (libpci, \\-lpci)")
 LINE("libpmc",		"Performance Counters Library (libpmc, \\-lpmc)")
 LINE("libposix",	"POSIX Compatibility Library (libposix, \\-lposix)")
+LINE("libppath",	"Property-List Paths Library (libppath, \\-lppath)")
 LINE("libprop",		"Property Container Object Library (libprop, \\-lprop)")
 LINE("libpthread",	"POSIX Threads Library (libpthread, \\-lpthread)")
 LINE("libpuffs",	"puffs Convenience Library (libpuffs, \\-lpuffs)")
+LINE("libquota",	"Disk Quota Access and Control Library (libquota, \\-lquota)")
 LINE("librefuse",	"File System in Userspace Convenience Library (librefuse, \\-lrefuse)")
 LINE("libresolv",	"DNS Resolver Library (libresolv, \\-lresolv)")
 LINE("librpcsec_gss",	"RPC GSS-API Authentication Library (librpcsec_gss, \\-lrpcsec_gss)")
 LINE("librpcsvc",	"RPC Service Library (librpcsvc, \\-lrpcsvc)")
-LINE("librt",		"POSIX Real\\-time Library (librt, -lrt)")
+LINE("librt",		"POSIX Real\\-time Library (librt, \\-lrt)")
+LINE("libsaslc",	"Simple Authentication and Security Layer client library (libsaslc, \\-lsaslc)")
 LINE("libsdp",		"Bluetooth Service Discovery Protocol User Library (libsdp, \\-lsdp)")
 LINE("libssp",		"Buffer Overflow Protection Library (libssp, \\-lssp)")
+LINE("libSystem",	"System Library (libSystem, \\-lSystem)")
 LINE("libtermcap",	"Termcap Access Library (libtermcap, \\-ltermcap)")
 LINE("libterminfo",	"Terminal Information Library (libterminfo, \\-lterminfo)")
 LINE("libthr",		"1:1 Threading Library (libthr, \\-lthr)")
diff --git a/external/bsd/mdocml/dist/libman.h b/external/bsd/mdocml/dist/libman.h
index fd37aa675..d229b24d2 100644
--- a/external/bsd/mdocml/dist/libman.h
+++ b/external/bsd/mdocml/dist/libman.h
@@ -1,6 +1,6 @@
-/*	$Vendor-Id: libman.h,v 1.44 2010/11/30 15:36:28 kristaps Exp $ */
+/*	$Vendor-Id: libman.h,v 1.55 2011/11/07 01:24:40 schwarze Exp $ */
 /*
- * Copyright (c) 2009, 2010 Kristaps Dzonsons 
+ * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons 
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -17,16 +17,13 @@
 #ifndef LIBMAN_H
 #define LIBMAN_H
 
-#include "man.h"
-
 enum	man_next {
 	MAN_NEXT_SIBLING = 0,
 	MAN_NEXT_CHILD
 };
 
 struct	man {
-	void		*data; /* private application data */
-	mandocmsg	 msg; /* output message handler */
+	struct mparse	*parse; /* parse pointer */
 	int		 flags; /* parse flags */
 #define	MAN_HALT	(1 << 0) /* badness happened: die */
 #define	MAN_ELINE	(1 << 1) /* Next-line element scope. */
@@ -34,11 +31,12 @@ struct	man {
 #define	MAN_ILINE	(1 << 3) /* Ignored in next-line scope. */
 #define	MAN_LITERAL	(1 << 4) /* Literal input. */
 #define	MAN_BPLINE	(1 << 5)
+#define	MAN_NEWLINE	(1 << 6) /* first macro/text in a line */
 	enum man_next	 next; /* where to put the next node */
 	struct man_node	*last; /* the last parsed node */
 	struct man_node	*first; /* the first parsed node */
 	struct man_meta	 meta; /* document meta-data */
-	struct regset	*regs; /* registers */
+	struct roff	*roff;
 };
 
 #define	MACRO_PROT_ARGS	  struct man *m, \
@@ -56,6 +54,7 @@ struct	man_macro {
 #define	MAN_FSCOPED	 (1 << 2)	/* See blk_imp(). */
 #define	MAN_NSCOPED	 (1 << 3)	/* See in_line_eoln(). */
 #define	MAN_NOCLOSE	 (1 << 4)	/* See blk_exp(). */
+#define	MAN_BSCOPE	 (1 << 5)	/* Break BLINE scope. */
 };
 
 extern	const struct man_macro *const man_macros;
@@ -63,25 +62,19 @@ extern	const struct man_macro *const man_macros;
 __BEGIN_DECLS
 
 #define		  man_pmsg(m, l, p, t) \
-		  (*(m)->msg)((t), (m)->data, (l), (p), NULL)
+		  mandoc_msg((t), (m)->parse, (l), (p), NULL)
 #define		  man_nmsg(m, n, t) \
-		  (*(m)->msg)((t), (m)->data, (n)->line, (n)->pos, NULL)
+		  mandoc_msg((t), (m)->parse, (n)->line, (n)->pos, NULL)
 int		  man_word_alloc(struct man *, int, int, const char *);
 int		  man_block_alloc(struct man *, int, int, enum mant);
 int		  man_head_alloc(struct man *, int, int, enum mant);
+int		  man_tail_alloc(struct man *, int, int, enum mant);
 int		  man_body_alloc(struct man *, int, int, enum mant);
 int		  man_elem_alloc(struct man *, int, int, enum mant);
 void		  man_node_delete(struct man *, struct man_node *);
 void		  man_hash_init(void);
-enum	mant	  man_hash_find(const char *);
+enum mant	  man_hash_find(const char *);
 int		  man_macroend(struct man *);
-int		  man_args(struct man *, int, int *, char *, char **);
-#define	ARGS_ERROR	(-1)
-#define	ARGS_EOLN	(0)
-#define	ARGS_WORD	(1)
-#define	ARGS_QWORD	(1)
-int		  man_vmsg(struct man *, enum mandocerr,
-			int, int, const char *, ...);
 int		  man_valid_post(struct man *);
 int		  man_valid_pre(struct man *, struct man_node *);
 int		  man_unscope(struct man *, 
diff --git a/external/bsd/mdocml/dist/libmandoc.h b/external/bsd/mdocml/dist/libmandoc.h
index ca05d9d17..8d8c6cdc3 100644
--- a/external/bsd/mdocml/dist/libmandoc.h
+++ b/external/bsd/mdocml/dist/libmandoc.h
@@ -1,6 +1,6 @@
-/*	$Vendor-Id: libmandoc.h,v 1.10 2011/01/03 22:42:37 schwarze Exp $ */
+/*	$Vendor-Id: libmandoc.h,v 1.29 2011/12/02 01:37:14 schwarze Exp $ */
 /*
- * Copyright (c) 2009, 2010 Kristaps Dzonsons 
+ * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons 
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -17,21 +17,75 @@
 #ifndef LIBMANDOC_H
 #define LIBMANDOC_H
 
+enum	rofferr {
+	ROFF_CONT, /* continue processing line */
+	ROFF_RERUN, /* re-run roff interpreter with offset */
+	ROFF_APPEND, /* re-run main parser, appending next line */
+	ROFF_REPARSE, /* re-run main parser on the result */
+	ROFF_SO, /* include another file */
+	ROFF_IGN, /* ignore current line */
+	ROFF_TBL, /* a table row was successfully parsed */
+	ROFF_EQN, /* an equation was successfully parsed */
+	ROFF_ERR /* badness: puke and stop */
+};
+
+enum	regs {
+	REG_nS = 0, /* nS register */
+	REG__MAX
+};
+
 __BEGIN_DECLS
 
-int		 mandoc_special(char *);
-void		*mandoc_calloc(size_t, size_t);
-char		*mandoc_strdup(const char *);
-void		*mandoc_malloc(size_t);
-void		*mandoc_realloc(void *, size_t);
-char		*mandoc_getarg(char **, mandocmsg, void *, int, int *);
-time_t		 mandoc_a2time(int, const char *);
-#define		 MTIME_CANONICAL	(1 << 0)
-#define		 MTIME_REDUCED		(1 << 1)
-#define		 MTIME_MDOCDATE		(1 << 2)
-#define		 MTIME_ISO_8601		(1 << 3)
+struct	roff;
+struct	mdoc;
+struct	man;
+
+void		 mandoc_msg(enum mandocerr, struct mparse *, 
+			int, int, const char *);
+void		 mandoc_vmsg(enum mandocerr, struct mparse *, 
+			int, int, const char *, ...);
+char		*mandoc_getarg(struct mparse *, char **, int, int *);
+char		*mandoc_normdate(struct mparse *, char *, int, int);
 int		 mandoc_eos(const char *, size_t, int);
-int		 mandoc_hyph(const char *, const char *);
+int		 mandoc_getcontrol(const char *, int *);
+int		 mandoc_strntoi(const char *, size_t, int);
+const char	*mandoc_a2msec(const char*);
+
+void	 	 mdoc_free(struct mdoc *);
+struct	mdoc	*mdoc_alloc(struct roff *, struct mparse *);
+void		 mdoc_reset(struct mdoc *);
+int	 	 mdoc_parseln(struct mdoc *, int, char *, int);
+int		 mdoc_endparse(struct mdoc *);
+int		 mdoc_addspan(struct mdoc *, const struct tbl_span *);
+int		 mdoc_addeqn(struct mdoc *, const struct eqn *);
+
+void	 	 man_free(struct man *);
+struct	man	*man_alloc(struct roff *, struct mparse *);
+void		 man_reset(struct man *);
+int	 	 man_parseln(struct man *, int, char *, int);
+int		 man_endparse(struct man *);
+int		 man_addspan(struct man *, const struct tbl_span *);
+int		 man_addeqn(struct man *, const struct eqn *);
+
+void	 	 roff_free(struct roff *);
+struct roff	*roff_alloc(struct mparse *);
+void		 roff_reset(struct roff *);
+enum rofferr	 roff_parseln(struct roff *, int, 
+			char **, size_t *, int, int *);
+void		 roff_endparse(struct roff *);
+int		 roff_regisset(const struct roff *, enum regs);
+unsigned int	 roff_regget(const struct roff *, enum regs);
+void		 roff_regunset(struct roff *, enum regs);
+char		*roff_strdup(const struct roff *, const char *);
+#if 0
+char		 roff_eqndelim(const struct roff *);
+void		 roff_openeqn(struct roff *, const char *, 
+			int, int, const char *);
+int		 roff_closeeqn(struct roff *);
+#endif
+
+const struct tbl_span	*roff_span(const struct roff *);
+const struct eqn	*roff_eqn(const struct roff *);
 
 __END_DECLS
 
diff --git a/external/bsd/mdocml/dist/libmdoc.h b/external/bsd/mdocml/dist/libmdoc.h
index 827960e5d..17d9fdf7d 100644
--- a/external/bsd/mdocml/dist/libmdoc.h
+++ b/external/bsd/mdocml/dist/libmdoc.h
@@ -1,6 +1,6 @@
-/*	$Vendor-Id: libmdoc.h,v 1.63 2010/11/30 13:04:14 kristaps Exp $ */
+/*	$Vendor-Id: libmdoc.h,v 1.78 2011/12/02 01:37:14 schwarze Exp $ */
 /*
- * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons 
+ * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons 
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -17,17 +17,14 @@
 #ifndef LIBMDOC_H
 #define LIBMDOC_H
 
-#include "mdoc.h"
-
 enum	mdoc_next {
 	MDOC_NEXT_SIBLING = 0,
 	MDOC_NEXT_CHILD
 };
 
 struct	mdoc {
-	void		 *data; /* private application data */
-	mandocmsg	  msg; /* message callback */
-	int		  flags;
+	struct mparse	 *parse; /* parse pointer */
+	int		  flags; /* parse flags */
 #define	MDOC_HALT	 (1 << 0) /* error in parse: halt */
 #define	MDOC_LITERAL	 (1 << 1) /* in a literal scope */
 #define	MDOC_PBODY	 (1 << 2) /* in the document body */
@@ -42,7 +39,7 @@ struct	mdoc {
 	struct mdoc_meta  meta; /* document meta-data */
 	enum mdoc_sec	  lastnamed;
 	enum mdoc_sec	  lastsec;
-	struct regset	 *regs; /* registers */
+	struct roff	 *roff;
 };
 
 #define	MACRO_PROT_ARGS	struct mdoc *m, \
@@ -65,27 +62,37 @@ struct	mdoc_macro {
 
 enum	margserr {
 	ARGS_ERROR,
-	ARGS_EOLN,
-	ARGS_WORD,
-	ARGS_PUNCT,
-	ARGS_QWORD,
-	ARGS_PHRASE,
-	ARGS_PPHRASE,
-	ARGS_PEND
+	ARGS_EOLN, /* end-of-line */
+	ARGS_WORD, /* normal word */
+	ARGS_PUNCT, /* series of punctuation */
+	ARGS_QWORD, /* quoted word */
+	ARGS_PHRASE, /* Ta'd phrase (-column) */
+	ARGS_PPHRASE, /* tabbed phrase (-column) */
+	ARGS_PEND /* last phrase (-column) */
 };
 
 enum	margverr {
 	ARGV_ERROR,
-	ARGV_EOLN,
-	ARGV_ARG,
-	ARGV_WORD
+	ARGV_EOLN, /* end of line */
+	ARGV_ARG, /* valid argument */
+	ARGV_WORD /* normal word (or bad argument---same thing) */
 };
 
+/*
+ * A punctuation delimiter is opening, closing, or "middle mark"
+ * punctuation.  These govern spacing.
+ * Opening punctuation (e.g., the opening parenthesis) suppresses the
+ * following space; closing punctuation (e.g., the closing parenthesis)
+ * suppresses the leading space; middle punctuation (e.g., the vertical
+ * bar) can do either.  The middle punctuation delimiter bends the rules
+ * depending on usage.
+ */
 enum	mdelim {
 	DELIM_NONE = 0,
 	DELIM_OPEN,
 	DELIM_MIDDLE,
-	DELIM_CLOSE
+	DELIM_CLOSE,
+	DELIM_MAX
 };
 
 extern	const struct mdoc_macro *const mdoc_macros;
@@ -93,11 +100,9 @@ extern	const struct mdoc_macro *const mdoc_macros;
 __BEGIN_DECLS
 
 #define		  mdoc_pmsg(m, l, p, t) \
-		  (*(m)->msg)((t), (m)->data, (l), (p), NULL)
+		  mandoc_msg((t), (m)->parse, (l), (p), NULL)
 #define		  mdoc_nmsg(m, n, t) \
-		  (*(m)->msg)((t), (m)->data, (n)->line, (n)->pos, NULL)
-int		  mdoc_vmsg(struct mdoc *, enum mandocerr, 
-			int, int, const char *, ...);
+		  mandoc_msg((t), (m)->parse, (n)->line, (n)->pos, NULL)
 int		  mdoc_macro(MACRO_PROT_ARGS);
 int		  mdoc_word_alloc(struct mdoc *, 
 			int, int, const char *);
@@ -114,33 +119,22 @@ int		  mdoc_endbody_alloc(struct mdoc *m, int line, int pos,
 void		  mdoc_node_delete(struct mdoc *, struct mdoc_node *);
 void		  mdoc_hash_init(void);
 enum mdoct	  mdoc_hash_find(const char *);
-enum mdelim	  mdoc_iscdelim(char);
-enum mdelim	  mdoc_isdelim(const char *);
-size_t		  mdoc_isescape(const char *);
-enum	mdoc_sec  mdoc_str2sec(const char *);
-time_t		  mdoc_atotime(const char *);
-size_t		  mdoc_macro2len(enum mdoct);
 const char	 *mdoc_a2att(const char *);
 const char	 *mdoc_a2lib(const char *);
 const char	 *mdoc_a2st(const char *);
 const char	 *mdoc_a2arch(const char *);
 const char	 *mdoc_a2vol(const char *);
-const char	 *mdoc_a2msec(const char *);
 int		  mdoc_valid_pre(struct mdoc *, struct mdoc_node *);
 int		  mdoc_valid_post(struct mdoc *);
 enum margverr	  mdoc_argv(struct mdoc *, int, enum mdoct,
 			struct mdoc_arg **, int *, char *);
 void		  mdoc_argv_free(struct mdoc_arg *);
-void		  mdoc_argn_free(struct mdoc_arg *, int);
 enum margserr	  mdoc_args(struct mdoc *, int,
 			int *, char *, enum mdoct, char **);
 enum margserr	  mdoc_zargs(struct mdoc *, int, 
-			int *, char *, int, char **);
-#define	ARGS_DELIM	(1 << 1)
-#define	ARGS_TABSEP	(1 << 2)
-#define	ARGS_NOWARN	(1 << 3)
-
+			int *, char *, char **);
 int		  mdoc_macroend(struct mdoc *);
+enum mdelim	  mdoc_isdelim(const char *);
 
 __END_DECLS
 
diff --git a/external/bsd/mdocml/dist/libroff.h b/external/bsd/mdocml/dist/libroff.h
index d9ba014f8..2036a1aac 100644
--- a/external/bsd/mdocml/dist/libroff.h
+++ b/external/bsd/mdocml/dist/libroff.h
@@ -1,6 +1,6 @@
-/*	$Vendor-Id: libroff.h,v 1.16 2011/01/04 15:02:00 kristaps Exp $ */
+/*	$Vendor-Id: libroff.h,v 1.27 2011/07/25 15:37:00 kristaps Exp $ */
 /*
- * Copyright (c) 2009, 2010 Kristaps Dzonsons 
+ * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons 
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -27,8 +27,7 @@ enum	tbl_part {
 };
 
 struct	tbl_node {
-	mandocmsg	  msg; /* status messages */
-	void		 *data; /* privdata for messages */
+	struct mparse	 *parse; /* parse point */
 	int		  pos; /* invocation column */
 	int		  line; /* invocation line */
 	enum tbl_part	  part;
@@ -36,16 +35,34 @@ struct	tbl_node {
 	struct tbl_row	 *first_row;
 	struct tbl_row	 *last_row;
 	struct tbl_span	 *first_span;
+	struct tbl_span	 *current_span;
 	struct tbl_span	 *last_span;
 	struct tbl_head	 *first_head;
 	struct tbl_head	 *last_head;
 	struct tbl_node	 *next;
 };
 
-#define	TBL_MSG(tblp, type, line, col) \
-	(*(tblp)->msg)((type), (tblp)->data, (line), (col), NULL)
+struct	eqn_node {
+	struct eqn_def	 *defs;
+	size_t		  defsz;
+	char		 *data;
+	size_t		  rew;
+	size_t		  cur;
+	size_t		  sz;
+	int		  gsize;
+	struct eqn	  eqn;
+	struct mparse	 *parse;
+	struct eqn_node  *next;
+};
 
-struct tbl_node	*tbl_alloc(int, int, void *, mandocmsg);
+struct	eqn_def {
+	char		 *key;
+	size_t		  keysz;
+	char		 *val;
+	size_t		  valsz;
+};
+
+struct tbl_node	*tbl_alloc(int, int, struct mparse *);
 void		 tbl_restart(int, int, struct tbl_node *);
 void		 tbl_free(struct tbl_node *);
 void		 tbl_reset(struct tbl_node *);
@@ -54,8 +71,13 @@ int		 tbl_option(struct tbl_node *, int, const char *);
 int		 tbl_layout(struct tbl_node *, int, const char *);
 int		 tbl_data(struct tbl_node *, int, const char *);
 int		 tbl_cdata(struct tbl_node *, int, const char *);
-const struct tbl_span *tbl_span(const struct tbl_node *);
-void		 tbl_end(struct tbl_node *);
+const struct tbl_span	*tbl_span(struct tbl_node *);
+void		 tbl_end(struct tbl_node **);
+struct eqn_node	*eqn_alloc(const char *, int, int, struct mparse *);
+enum rofferr	 eqn_end(struct eqn_node **);
+void		 eqn_free(struct eqn_node *);
+enum rofferr 	 eqn_read(struct eqn_node **, int, 
+			const char *, int, int *);
 
 __END_DECLS
 
diff --git a/external/bsd/mdocml/dist/main.c b/external/bsd/mdocml/dist/main.c
index 8418744f2..d59257740 100644
--- a/external/bsd/mdocml/dist/main.c
+++ b/external/bsd/mdocml/dist/main.c
@@ -1,7 +1,7 @@
-/*	$Vendor-Id: main.c,v 1.135 2011/01/04 15:02:00 kristaps Exp $ */
+/*	$Vendor-Id: main.c,v 1.165 2011/10/06 22:29:12 kristaps Exp $ */
 /*
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons 
- * Copyright (c) 2010 Ingo Schwarze 
+ * Copyright (c) 2010, 2011 Ingo Schwarze 
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -19,14 +19,7 @@
 #include "config.h"
 #endif
 
-#ifndef __minix
-#include 
-#endif
-#include 
-
 #include 
-#include 
-#include 
 #include 
 #include 
 #include 
@@ -37,16 +30,6 @@
 #include "main.h"
 #include "mdoc.h"
 #include "man.h"
-#include "roff.h"
-
-#ifndef MAP_FILE
-#define	MAP_FILE	0
-#endif
-
-#define	REPARSE_LIMIT	1000
-#define	UNCONST(a)	((void *)(uintptr_t)(const void *)(a))
-
-/* FIXME: Intel's compiler?  LLVM?  pcc?  */
 
 #if !defined(__GNUC__) || (__GNUC__ < 2)
 # if !defined(lint)
@@ -58,41 +41,23 @@ typedef	void		(*out_mdoc)(void *, const struct mdoc *);
 typedef	void		(*out_man)(void *, const struct man *);
 typedef	void		(*out_free)(void *);
 
-struct	buf {
-	char	 	 *buf;
-	size_t		  sz;
-};
-
-enum	intt {
-	INTT_AUTO,
-	INTT_MDOC,
-	INTT_MAN
-};
-
 enum	outt {
-	OUTT_ASCII = 0,
-	OUTT_TREE,
-	OUTT_HTML,
-	OUTT_XHTML,
-	OUTT_LINT,
-	OUTT_PS,
-	OUTT_PDF
+	OUTT_ASCII = 0,	/* -Tascii */
+	OUTT_LOCALE,	/* -Tlocale */
+	OUTT_UTF8,	/* -Tutf8 */
+	OUTT_TREE,	/* -Ttree */
+	OUTT_MAN,	/* -Tman */
+	OUTT_HTML,	/* -Thtml */
+	OUTT_XHTML,	/* -Txhtml */
+	OUTT_LINT,	/* -Tlint */
+	OUTT_PS,	/* -Tps */
+	OUTT_PDF	/* -Tpdf */
 };
 
 struct	curparse {
-	const char	 *file;		/* Current parse. */
-	int		  fd;		/* Current parse. */
-	int		  line;		/* Line number in the file. */
-	enum mandoclevel  wlevel;	/* Ignore messages below this. */
-	int		  wstop;	/* Stop after a file with a warning. */
-	enum intt	  inttype;	/* which parser to use */
-	struct man	 *pman;		/* persistent man parser */
-	struct mdoc	 *pmdoc;	/* persistent mdoc parser */
-	struct man	 *man;		/* man parser */
-	struct mdoc	 *mdoc;		/* mdoc parser */
-	struct roff	 *roff;		/* roff parser (!NULL) */
-	struct regset	  regs;		/* roff registers */
-	int		  reparse_count; /* finite interpolation stack */
+	struct mparse	 *mp;
+	enum mandoclevel  wlevel;	/* ignore messages below this */
+	int		  wstop;	/* stop after a file with a warning */
 	enum outt	  outtype; 	/* which output to use */
 	out_mdoc	  outmdoc;	/* mdoc output ptr */
 	out_man	  	  outman;	/* man output ptr */
@@ -101,154 +66,25 @@ struct	curparse {
 	char		  outopts[BUFSIZ]; /* buf of output opts */
 };
 
-static	const char * const	mandoclevels[MANDOCLEVEL_MAX] = {
-	"SUCCESS",
-	"RESERVED",
-	"WARNING",
-	"ERROR",
-	"FATAL",
-	"BADARG",
-	"SYSERR"
-};
-
-static	const enum mandocerr	mandoclimits[MANDOCLEVEL_MAX] = {
-	MANDOCERR_OK,
-	MANDOCERR_WARNING,
-	MANDOCERR_WARNING,
-	MANDOCERR_ERROR,
-	MANDOCERR_FATAL,
-	MANDOCERR_MAX,
-	MANDOCERR_MAX
-};
-
-static	const char * const	mandocerrs[MANDOCERR_MAX] = {
-	"ok",
-
-	"generic warning",
-
-	/* related to the prologue */
-	"no title in document",
-	"document title should be all caps",
-	"unknown manual section",
-	"cannot parse date argument",
-	"prologue macros out of order",
-	"duplicate prologue macro",
-	"macro not allowed in prologue",
-	"macro not allowed in body",
-
-	/* related to document structure */
-	".so is fragile, better use ln(1)",
-	"NAME section must come first",
-	"bad NAME section contents",
-	"manual name not yet set",
-	"sections out of conventional order",
-	"duplicate section name",
-	"section not in conventional manual section",
-
-	/* related to macros and nesting */
-	"skipping obsolete macro",
-	"skipping paragraph macro",
-	"blocks badly nested",
-	"child violates parent syntax",
-	"nested displays are not portable",
-	"already in literal mode",
-
-	/* related to missing macro arguments */
-	"skipping empty macro",
-	"argument count wrong",
-	"missing display type",
-	"list type must come first",
-	"tag lists require a width argument",
-	"missing font type",
-
-	/* related to bad macro arguments */
-	"skipping argument",
-	"duplicate argument",
-	"duplicate display type",
-	"duplicate list type",
-	"unknown AT&T UNIX version",
-	"bad Boolean value",
-	"unknown font",
-	"unknown standard specifier",
-	"bad width argument",
-
-	/* related to plain text */
-	"blank line in non-literal context",
-	"tab in non-literal context",
-	"end of line whitespace",
-	"bad comment style",
-	"unknown escape sequence",
-	"unterminated quoted string",
-	
-	/* related to tables */
-	"extra data cells",
-
-	"generic error",
-
-	/* related to tables */
-	"bad table syntax",
-	"bad table option",
-	"bad table layout",
-	"no table layout cells specified",
-	"no table data cells specified",
-	"ignore data in cell",
-	"data block still open",
-
-	"input stack limit exceeded, infinite loop?",
-	"skipping bad character",
-	"skipping text before the first section header",
-	"skipping unknown macro",
-	"NOT IMPLEMENTED: skipping request",
-	"line scope broken",
-	"argument count wrong",
-	"skipping end of block that is not open",
-	"missing end of block",
-	"scope open on exit",
-	"uname(3) system call failed",
-	"macro requires line argument(s)",
-	"macro requires body argument(s)",
-	"macro requires argument(s)",
-	"missing list type",
-	"line argument(s) will be lost",
-	"body argument(s) will be lost",
-
-	"generic fatal error",
-
-	"column syntax is inconsistent",
-	"NOT IMPLEMENTED: .Bd -file",
-	"line scope broken, syntax violated",
-	"argument count wrong, violates syntax",
-	"child violates parent syntax",
-	"argument count wrong, violates syntax",
-	"NOT IMPLEMENTED: .so with absolute path or \"..\"",
-	"no document body",
-	"no document prologue",
-	"static buffer exhausted",
-};
-
-static	void		  parsebuf(struct curparse *, struct buf, int);
-static	void		  pdesc(struct curparse *);
-static	void		  fdesc(struct curparse *);
-static	void		  ffile(const char *, struct curparse *);
-static	int		  pfile(const char *, struct curparse *);
-static	int		  moptions(enum intt *, char *);
-static	int		  mmsg(enum mandocerr, void *, 
-				int, int, const char *);
-static	void		  pset(const char *, int, struct curparse *);
+static	int		  moptions(enum mparset *, char *);
+static	void		  mmsg(enum mandocerr, enum mandoclevel,
+				const char *, int, int, const char *);
+static	void		  parse(struct curparse *, int, 
+				const char *, enum mandoclevel *);
 static	int		  toptions(struct curparse *, char *);
 static	void		  usage(void) __attribute__((noreturn));
 static	void		  version(void) __attribute__((noreturn));
 static	int		  woptions(struct curparse *, char *);
 
 static	const char	 *progname;
-static	enum mandoclevel  file_status = MANDOCLEVEL_OK;
-static	enum mandoclevel  exit_status = MANDOCLEVEL_OK;
 
 int
 main(int argc, char *argv[])
 {
 	int		 c;
 	struct curparse	 curp;
+	enum mparset	 type;
+	enum mandoclevel rc;
 
 	progname = strrchr(argv[0], '/');
 	if (progname == NULL)
@@ -258,7 +94,7 @@ main(int argc, char *argv[])
 
 	memset(&curp, 0, sizeof(struct curparse));
 
-	curp.inttype = INTT_AUTO;
+	type = MPARSE_AUTO;
 	curp.outtype = OUTT_ASCII;
 	curp.wlevel  = MANDOCLEVEL_FATAL;
 
@@ -266,7 +102,7 @@ main(int argc, char *argv[])
 	while (-1 != (c = getopt(argc, argv, "m:O:T:VW:")))
 		switch (c) {
 		case ('m'):
-			if ( ! moptions(&curp.inttype, optarg))
+			if ( ! moptions(&type, optarg))
 				return((int)MANDOCLEVEL_BADARG);
 			break;
 		case ('O'):
@@ -289,56 +125,56 @@ main(int argc, char *argv[])
 			/* NOTREACHED */
 		}
 
+	curp.mp = mparse_alloc(type, curp.wlevel, mmsg, &curp);
+
+	/*
+	 * Conditionally start up the lookaside buffer before parsing.
+	 */
+	if (OUTT_MAN == curp.outtype)
+		mparse_keep(curp.mp);
+
 	argc -= optind;
 	argv += optind;
 
-	if (NULL == *argv) {
-		curp.file = "";
-		curp.fd = STDIN_FILENO;
+	rc = MANDOCLEVEL_OK;
 
-		fdesc(&curp);
-	}
+	if (NULL == *argv)
+		parse(&curp, STDIN_FILENO, "", &rc);
 
 	while (*argv) {
-		ffile(*argv, &curp);
-		if (MANDOCLEVEL_OK != exit_status && curp.wstop)
+		parse(&curp, -1, *argv, &rc);
+		if (MANDOCLEVEL_OK != rc && curp.wstop)
 			break;
 		++argv;
 	}
 
 	if (curp.outfree)
 		(*curp.outfree)(curp.outdata);
-	if (curp.pmdoc)
-		mdoc_free(curp.pmdoc);
-	if (curp.pman)
-		man_free(curp.pman);
-	if (curp.roff)
-		roff_free(curp.roff);
+	if (curp.mp)
+		mparse_free(curp.mp);
 
-	return((int)exit_status);
+	return((int)rc);
 }
 
-
 static void
 version(void)
 {
 
-	(void)printf("%s %s\n", progname, VERSION);
+	printf("%s %s\n", progname, VERSION);
 	exit((int)MANDOCLEVEL_OK);
 }
 
-
 static void
 usage(void)
 {
 
-	(void)fprintf(stderr, "usage: %s "
+	fprintf(stderr, "usage: %s "
 			"[-V] "
 			"[-foption] "
 			"[-mformat] "
 			"[-Ooption] "
 			"[-Toutput] "
-			"[-Werr] "
+			"[-Wlevel] "
 			"[file...]\n", 
 			progname);
 
@@ -346,207 +182,31 @@ usage(void)
 }
 
 static void
-ffile(const char *file, struct curparse *curp)
+parse(struct curparse *curp, int fd, 
+		const char *file, enum mandoclevel *level)
 {
+	enum mandoclevel  rc;
+	struct mdoc	 *mdoc;
+	struct man	 *man;
 
-	/*
-	 * Called once per input file.  Get the file ready for reading,
-	 * pass it through to the parser-driver, then close it out.
-	 * XXX: don't do anything special as this is only called for
-	 * files; stdin goes directly to fdesc().
-	 */
+	/* Begin by parsing the file itself. */
 
-	curp->file = file;
+	assert(file);
+	assert(fd >= -1);
 
-	if (-1 == (curp->fd = open(curp->file, O_RDONLY, 0))) {
-		perror(curp->file);
-		exit_status = MANDOCLEVEL_SYSERR;
-		return;
-	}
+	rc = mparse_readfd(curp->mp, fd, file);
 
-	fdesc(curp);
+	/* Stop immediately if the parse has failed. */
 
-	if (-1 == close(curp->fd))
-		perror(curp->file);
-}
-
-static int
-pfile(const char *file, struct curparse *curp)
-{
-	const char	*savefile;
-	int		 fd, savefd;
-
-	if (-1 == (fd = open(file, O_RDONLY, 0))) {
-		perror(file);
-		file_status = MANDOCLEVEL_SYSERR;
-		return(0);
-	}
-
-	savefile = curp->file;
-	savefd = curp->fd;
-
-	curp->file = file;
-	curp->fd = fd;
-
-	pdesc(curp);
-
-	curp->file = savefile;
-	curp->fd = savefd;
-
-	if (-1 == close(fd))
-		perror(file);
-
-	return(MANDOCLEVEL_FATAL > file_status ? 1 : 0);
-}
-
-
-static void
-resize_buf(struct buf *buf, size_t initial)
-{
-
-	buf->sz = buf->sz > initial/2 ? 2 * buf->sz : initial;
-	buf->buf = realloc(buf->buf, buf->sz);
-	if (NULL == buf->buf) {
-		perror(NULL);
-		exit((int)MANDOCLEVEL_SYSERR);
-	}
-}
-
-
-static int
-read_whole_file(struct curparse *curp, struct buf *fb, int *with_mmap)
-{
-	struct stat	 st;
-	size_t		 off;
-	ssize_t		 ssz;
-
-	if (-1 == fstat(curp->fd, &st)) {
-		perror(curp->file);
-		return(0);
-	}
-
-	/*
-	 * If we're a regular file, try just reading in the whole entry
-	 * via mmap().  This is faster than reading it into blocks, and
-	 * since each file is only a few bytes to begin with, I'm not
-	 * concerned that this is going to tank any machines.
-	 */
-
-#ifndef __minix
-	if (S_ISREG(st.st_mode)) {
-		if (st.st_size >= (1U << 31)) {
-			fprintf(stderr, "%s: input too large\n", 
-					curp->file);
-			return(0);
-		}
-		*with_mmap = 1;
-		fb->sz = (size_t)st.st_size;
-		fb->buf = mmap(NULL, fb->sz, PROT_READ, 
-				MAP_FILE|MAP_SHARED, curp->fd, 0);
-		if (fb->buf != MAP_FAILED)
-			return(1);
-	}
-#endif
-
-	/*
-	 * If this isn't a regular file (like, say, stdin), then we must
-	 * go the old way and just read things in bit by bit.
-	 */
-
-	*with_mmap = 0;
-	off = 0;
-	fb->sz = 0;
-	fb->buf = NULL;
-	for (;;) {
-		if (off == fb->sz) {
-			if (fb->sz == (1U << 31)) {
-				fprintf(stderr, "%s: input too large\n", 
-						curp->file);
-				break;
-			}
-			resize_buf(fb, 65536);
-		}
-		ssz = read(curp->fd, fb->buf + (int)off, fb->sz - off);
-		if (ssz == 0) {
-			fb->sz = off;
-			return(1);
-		}
-		if (ssz == -1) {
-			perror(curp->file);
-			break;
-		}
-		off += (size_t)ssz;
-	}
-
-	free(fb->buf);
-	fb->buf = NULL;
-	return(0);
-}
-
-
-static void
-fdesc(struct curparse *curp)
-{
-
-	/*
-	 * Called once per file with an opened file descriptor.  All
-	 * pre-file-parse operations (whether stdin or a file) should go
-	 * here.
-	 *
-	 * This calls down into the nested parser, which drills down and
-	 * fully parses a file and all its dependences (i.e., `so').  It
-	 * then runs the cleanup validators and pushes to output.
-	 */
-
-	/* Zero the parse type. */
-
-	curp->mdoc = NULL;
-	curp->man = NULL;
-	file_status = MANDOCLEVEL_OK;
-
-	/* Make sure the mandotory roff parser is initialised. */
-
-	if (NULL == curp->roff) {
-		curp->roff = roff_alloc(&curp->regs, curp, mmsg);
-		assert(curp->roff);
-	}
-
-	/* Fully parse the file. */
-
-	pdesc(curp);
-
-	if (MANDOCLEVEL_FATAL <= file_status)
+	if (MANDOCLEVEL_FATAL <= rc)
 		goto cleanup;
 
-	/* NOTE a parser may not have been assigned, yet. */
-
-	if ( ! (curp->man || curp->mdoc)) {
-		fprintf(stderr, "%s: Not a manual\n", curp->file);
-		file_status = MANDOCLEVEL_FATAL;
-		goto cleanup;
-	}
-
-	/* Clean up the parse routine ASTs. */
-
-	if (curp->mdoc && ! mdoc_endparse(curp->mdoc)) {
-		assert(MANDOCLEVEL_FATAL <= file_status);
-		goto cleanup;
-	}
-
-	if (curp->man && ! man_endparse(curp->man)) {
-		assert(MANDOCLEVEL_FATAL <= file_status);
-		goto cleanup;
-	}
-
-	assert(curp->roff);
-	roff_endparse(curp->roff);
-
 	/*
-	 * With -Wstop and warnings or errors of at least
-	 * the requested level, do not produce output.
+	 * With -Wstop and warnings or errors of at least the requested
+	 * level, do not produce output.
 	 */
 
-	if (MANDOCLEVEL_OK != file_status && curp->wstop)
+	if (MANDOCLEVEL_OK != rc && curp->wstop)
 		goto cleanup;
 
 	/* If unset, allocate output dev now (if applicable). */
@@ -555,9 +215,19 @@ fdesc(struct curparse *curp)
 		switch (curp->outtype) {
 		case (OUTT_XHTML):
 			curp->outdata = xhtml_alloc(curp->outopts);
+			curp->outfree = html_free;
 			break;
 		case (OUTT_HTML):
 			curp->outdata = html_alloc(curp->outopts);
+			curp->outfree = html_free;
+			break;
+		case (OUTT_UTF8):
+			curp->outdata = utf8_alloc(curp->outopts);
+			curp->outfree = ascii_free;
+			break;
+		case (OUTT_LOCALE):
+			curp->outdata = locale_alloc(curp->outopts);
+			curp->outfree = ascii_free;
 			break;
 		case (OUTT_ASCII):
 			curp->outdata = ascii_alloc(curp->outopts);
@@ -581,16 +251,23 @@ fdesc(struct curparse *curp)
 		case (OUTT_XHTML):
 			curp->outman = html_man;
 			curp->outmdoc = html_mdoc;
-			curp->outfree = html_free;
 			break;
 		case (OUTT_TREE):
 			curp->outman = tree_man;
 			curp->outmdoc = tree_mdoc;
 			break;
+		case (OUTT_MAN):
+			curp->outmdoc = man_mdoc;
+			curp->outman = man_man;
+			break;
 		case (OUTT_PDF):
 			/* FALLTHROUGH */
 		case (OUTT_ASCII):
 			/* FALLTHROUGH */
+		case (OUTT_UTF8):
+			/* FALLTHROUGH */
+		case (OUTT_LOCALE):
+			/* FALLTHROUGH */
 		case (OUTT_PS):
 			curp->outman = terminal_man;
 			curp->outmdoc = terminal_mdoc;
@@ -600,349 +277,33 @@ fdesc(struct curparse *curp)
 		}
 	}
 
+	mparse_result(curp->mp, &mdoc, &man);
+
 	/* Execute the out device, if it exists. */
 
-	if (curp->man && curp->outman)
-		(*curp->outman)(curp->outdata, curp->man);
-	if (curp->mdoc && curp->outmdoc)
-		(*curp->outmdoc)(curp->outdata, curp->mdoc);
+	if (man && curp->outman)
+		(*curp->outman)(curp->outdata, man);
+	if (mdoc && curp->outmdoc)
+		(*curp->outmdoc)(curp->outdata, mdoc);
 
  cleanup:
 
-	memset(&curp->regs, 0, sizeof(struct regset));
+	mparse_reset(curp->mp);
 
-	/* Reset the current-parse compilers. */
-
-	if (curp->mdoc)
-		mdoc_reset(curp->mdoc);
-	if (curp->man)
-		man_reset(curp->man);
-
-	assert(curp->roff);
-	roff_reset(curp->roff);
-
-	if (exit_status < file_status)
-		exit_status = file_status;
-
-	return;
-}
-
-static void
-pdesc(struct curparse *curp)
-{
-	struct buf	 blk;
-	int		 with_mmap;
-
-	/*
-	 * Run for each opened file; may be called more than once for
-	 * each full parse sequence if the opened file is nested (i.e.,
-	 * from `so').  Simply sucks in the whole file and moves into
-	 * the parse phase for the file.
-	 */
-
-	if ( ! read_whole_file(curp, &blk, &with_mmap)) {
-		file_status = MANDOCLEVEL_SYSERR;
-		return;
-	}
-
-	/* Line number is per-file. */
-
-	curp->line = 1;
-
-	parsebuf(curp, blk, 1);
-
-#ifndef __minix
-	if (with_mmap)
-		munmap(blk.buf, blk.sz);
-	else
-#endif
-		free(blk.buf);
-}
-
-static void
-parsebuf(struct curparse *curp, struct buf blk, int start)
-{
-	struct buf	 ln;
-	enum rofferr	 rr;
-	int		 i, of, rc;
-	int		 pos; /* byte number in the ln buffer */
-	int		 lnn; /* line number in the real file */
-	unsigned char	 c;
-
-	/*
-	 * Main parse routine for an opened file.  This is called for
-	 * each opened file and simply loops around the full input file,
-	 * possibly nesting (i.e., with `so').
-	 */
-
-	memset(&ln, 0, sizeof(struct buf));
-
-	lnn = curp->line; 
-	pos = 0; 
-
-	for (i = 0; i < (int)blk.sz; ) {
-		if (0 == pos && '\0' == blk.buf[i])
-			break;
-
-		if (start) {
-			curp->line = lnn;
-			curp->reparse_count = 0;
-		}
-
-		while (i < (int)blk.sz && (start || '\0' != blk.buf[i])) {
-			if ('\n' == blk.buf[i]) {
-				++i;
-				++lnn;
-				break;
-			}
-
-			/* 
-			 * Warn about bogus characters.  If you're using
-			 * non-ASCII encoding, you're screwing your
-			 * readers.  Since I'd rather this not happen,
-			 * I'll be helpful and drop these characters so
-			 * we don't display gibberish.  Note to manual
-			 * writers: use special characters.
-			 */
-
-			c = (unsigned char) blk.buf[i];
-
-			if ( ! (isascii(c) && 
-					(isgraph(c) || isblank(c)))) {
-				mmsg(MANDOCERR_BADCHAR, curp, 
-				    curp->line, pos, "ignoring byte");
-				i++;
-				continue;
-			}
-
-			/* Trailing backslash = a plain char. */
-
-			if ('\\' != blk.buf[i] || i + 1 == (int)blk.sz) {
-				if (pos >= (int)ln.sz)
-					resize_buf(&ln, 256);
-				ln.buf[pos++] = blk.buf[i++];
-				continue;
-			}
-
-			/* Found escape & at least one other char. */
-
-			if ('\n' == blk.buf[i + 1]) {
-				i += 2;
-				/* Escaped newlines are skipped over */
-				++lnn;
-				continue;
-			}
-
-			if ('"' == blk.buf[i + 1]) {
-				i += 2;
-				/* Comment, skip to end of line */
-				for (; i < (int)blk.sz; ++i) {
-					if ('\n' == blk.buf[i]) {
-						++i;
-						++lnn;
-						break;
-					}
-				}
-
-				/* Backout trailing whitespaces */
-				for (; pos > 0; --pos) {
-					if (ln.buf[pos - 1] != ' ')
-						break;
-					if (pos > 2 && ln.buf[pos - 2] == '\\')
-						break;
-				}
-				break;
-			}
-
-			/* Some other escape sequence, copy & cont. */
-
-			if (pos + 1 >= (int)ln.sz)
-				resize_buf(&ln, 256);
-
-			ln.buf[pos++] = blk.buf[i++];
-			ln.buf[pos++] = blk.buf[i++];
-		}
-
- 		if (pos >= (int)ln.sz)
-			resize_buf(&ln, 256);
-
-		ln.buf[pos] = '\0';
-
-		/*
-		 * A significant amount of complexity is contained by
-		 * the roff preprocessor.  It's line-oriented but can be
-		 * expressed on one line, so we need at times to
-		 * readjust our starting point and re-run it.  The roff
-		 * preprocessor can also readjust the buffers with new
-		 * data, so we pass them in wholesale.
-		 */
-
-		of = 0;
-
-rerun:
-		rr = roff_parseln
-			(curp->roff, curp->line, 
-			 &ln.buf, &ln.sz, of, &of);
-
-		switch (rr) {
-		case (ROFF_REPARSE):
-			if (REPARSE_LIMIT >= ++curp->reparse_count)
-				parsebuf(curp, ln, 0);
-			else
-				mmsg(MANDOCERR_ROFFLOOP, curp, 
-				    curp->line, pos, NULL);
-			pos = 0;
-			continue;
-		case (ROFF_APPEND):
-			pos = strlen(ln.buf);
-			continue;
-		case (ROFF_RERUN):
-			goto rerun;
-		case (ROFF_IGN):
-			pos = 0;
-			continue;
-		case (ROFF_ERR):
-			assert(MANDOCLEVEL_FATAL <= file_status);
-			break;
-		case (ROFF_SO):
-			if (pfile(ln.buf + of, curp)) {
-				pos = 0;
-				continue;
-			} else
-				break;
-		default:
-			break;
-		}
-
-		/*
-		 * If we encounter errors in the recursive parsebuf()
-		 * call, make sure we don't continue parsing.
-		 */
-
-		if (MANDOCLEVEL_FATAL <= file_status)
-			break;
-
-		/*
-		 * If input parsers have not been allocated, do so now.
-		 * We keep these instanced betwen parsers, but set them
-		 * locally per parse routine since we can use different
-		 * parsers with each one.
-		 */
-
-		if ( ! (curp->man || curp->mdoc))
-			pset(ln.buf + of, pos - of, curp);
-
-		/* 
-		 * Lastly, push down into the parsers themselves.  One
-		 * of these will have already been set in the pset()
-		 * routine.
-		 * If libroff returns ROFF_TBL, then add it to the
-		 * currently open parse.  Since we only get here if
-		 * there does exist data (see tbl_data.c), we're
-		 * guaranteed that something's been allocated.
-		 */
-
-		if (ROFF_TBL == rr) {
-			assert(curp->man || curp->mdoc);
-			if (curp->man)
-				man_addspan(curp->man, roff_span(curp->roff));
-			else
-				mdoc_addspan(curp->mdoc, roff_span(curp->roff));
-
-		} else if (curp->man || curp->mdoc) {
-			rc = curp->man ?
-				man_parseln(curp->man, 
-					curp->line, ln.buf, of) :
-				mdoc_parseln(curp->mdoc, 
-					curp->line, ln.buf, of);
-
-			if ( ! rc) {
-				assert(MANDOCLEVEL_FATAL <= file_status);
-				break;
-			}
-		}
-
-		/* Temporary buffers typically are not full. */
-
-		if (0 == start && '\0' == blk.buf[i])
-			break;
-
-		/* Start the next input line. */
-
-		pos = 0;
-	}
-
-	free(ln.buf);
-}
-
-static void
-pset(const char *buf, int pos, struct curparse *curp)
-{
-	int		 i;
-
-	/*
-	 * Try to intuit which kind of manual parser should be used.  If
-	 * passed in by command-line (-man, -mdoc), then use that
-	 * explicitly.  If passed as -mandoc, then try to guess from the
-	 * line: either skip dot-lines, use -mdoc when finding `.Dt', or
-	 * default to -man, which is more lenient.
-	 *
-	 * Separate out pmdoc/pman from mdoc/man: the first persists
-	 * through all parsers, while the latter is used per-parse.
-	 */
-
-	if ('.' == buf[0] || '\'' == buf[0]) {
-		for (i = 1; buf[i]; i++)
-			if (' ' != buf[i] && '\t' != buf[i])
-				break;
-		if ('\0' == buf[i])
-			return;
-	}
-
-	switch (curp->inttype) {
-	case (INTT_MDOC):
-		if (NULL == curp->pmdoc) 
-			curp->pmdoc = mdoc_alloc
-				(&curp->regs, curp, mmsg);
-		assert(curp->pmdoc);
-		curp->mdoc = curp->pmdoc;
-		return;
-	case (INTT_MAN):
-		if (NULL == curp->pman) 
-			curp->pman = man_alloc
-				(&curp->regs, curp, mmsg);
-		assert(curp->pman);
-		curp->man = curp->pman;
-		return;
-	default:
-		break;
-	}
-
-	if (pos >= 3 && 0 == memcmp(buf, ".Dd", 3))  {
-		if (NULL == curp->pmdoc) 
-			curp->pmdoc = mdoc_alloc
-				(&curp->regs, curp, mmsg);
-		assert(curp->pmdoc);
-		curp->mdoc = curp->pmdoc;
-		return;
-	} 
-
-	if (NULL == curp->pman) 
-		curp->pman = man_alloc(&curp->regs, curp, mmsg);
-	assert(curp->pman);
-	curp->man = curp->pman;
+	if (*level < rc)
+		*level = rc;
 }
 
 static int
-moptions(enum intt *tflags, char *arg)
+moptions(enum mparset *tflags, char *arg)
 {
 
 	if (0 == strcmp(arg, "doc"))
-		*tflags = INTT_MDOC;
+		*tflags = MPARSE_MDOC;
 	else if (0 == strcmp(arg, "andoc"))
-		*tflags = INTT_AUTO;
+		*tflags = MPARSE_AUTO;
 	else if (0 == strcmp(arg, "an"))
-		*tflags = INTT_MAN;
+		*tflags = MPARSE_MAN;
 	else {
 		fprintf(stderr, "%s: Bad argument\n", arg);
 		return(0);
@@ -960,11 +321,16 @@ toptions(struct curparse *curp, char *arg)
 	else if (0 == strcmp(arg, "lint")) {
 		curp->outtype = OUTT_LINT;
 		curp->wlevel  = MANDOCLEVEL_WARNING;
-	}
-	else if (0 == strcmp(arg, "tree"))
+	} else if (0 == strcmp(arg, "tree"))
 		curp->outtype = OUTT_TREE;
+	else if (0 == strcmp(arg, "man"))
+		curp->outtype = OUTT_MAN;
 	else if (0 == strcmp(arg, "html"))
 		curp->outtype = OUTT_HTML;
+	else if (0 == strcmp(arg, "utf8"))
+		curp->outtype = OUTT_UTF8;
+	else if (0 == strcmp(arg, "locale"))
+		curp->outtype = OUTT_LOCALE;
 	else if (0 == strcmp(arg, "xhtml"))
 		curp->outtype = OUTT_XHTML;
 	else if (0 == strcmp(arg, "ps"))
@@ -1018,29 +384,18 @@ woptions(struct curparse *curp, char *arg)
 	return(1);
 }
 
-static int
-mmsg(enum mandocerr t, void *arg, int ln, int col, const char *msg)
+static void
+mmsg(enum mandocerr t, enum mandoclevel lvl, 
+		const char *file, int line, int col, const char *msg)
 {
-	struct curparse *cp;
-	enum mandoclevel level;
 
-	level = MANDOCLEVEL_FATAL;
-	while (t < mandoclimits[level])
-		/* LINTED */
-		level--;
+	fprintf(stderr, "%s:%d:%d: %s: %s", 
+			file, line, col + 1, 
+			mparse_strlevel(lvl),
+			mparse_strerror(t));
 
-	cp = (struct curparse *)arg;
-	if (level < cp->wlevel)
-		return(1);
-
-	fprintf(stderr, "%s:%d:%d: %s: %s",
-	    cp->file, ln, col + 1, mandoclevels[level], mandocerrs[t]);
 	if (msg)
 		fprintf(stderr, ": %s", msg);
-	fputc('\n', stderr);
 
-	if (file_status < level)
-		file_status = level;
-	
-	return(level < MANDOCLEVEL_FATAL);
+	fputc('\n', stderr);
 }
diff --git a/external/bsd/mdocml/dist/main.h b/external/bsd/mdocml/dist/main.h
index 8d839f2fd..9395eba15 100644
--- a/external/bsd/mdocml/dist/main.h
+++ b/external/bsd/mdocml/dist/main.h
@@ -1,6 +1,6 @@
-/*	$Vendor-Id: main.h,v 1.10 2010/07/31 23:52:58 schwarze Exp $ */
+/*	$Vendor-Id: main.h,v 1.15 2011/10/06 22:29:12 kristaps Exp $ */
 /*
- * Copyright (c) 2009, 2010 Kristaps Dzonsons 
+ * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons 
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -41,6 +41,11 @@ void		  html_free(void *);
 void		  tree_mdoc(void *, const struct mdoc *);
 void		  tree_man(void *, const struct man *);
 
+void		  man_mdoc(void *, const struct mdoc *);
+void		  man_man(void *, const struct man *);
+
+void		 *locale_alloc(char *);
+void		 *utf8_alloc(char *);
 void		 *ascii_alloc(char *);
 void		  ascii_free(void *);
 
diff --git a/external/bsd/mdocml/dist/man-cgi.css b/external/bsd/mdocml/dist/man-cgi.css
new file mode 100644
index 000000000..5300267cf
--- /dev/null
+++ b/external/bsd/mdocml/dist/man-cgi.css
@@ -0,0 +1,13 @@
+body				{ font-family: Helvetica, Arial, sans-serif; }
+body > div			{ padding-left: 2em; 
+				  padding-top: 1em; }
+body > div#mancgi		{ padding-left: 0em; 
+				  padding-top: 0em; }
+body > div.results		{ font-size: smaller; }
+#mancgi fieldset		{ text-align: center; 
+				  border: thin solid silver;
+				  border-radius: 1em;
+			  	  font-size: small; }
+#mancgi input[name=expr] 	{ width: 25%; }
+.results td.title		{ vertical-align: top;
+				  padding-right: 1em; }
diff --git a/external/bsd/mdocml/dist/man.3 b/external/bsd/mdocml/dist/man.3
deleted file mode 100644
index 78edcefff..000000000
--- a/external/bsd/mdocml/dist/man.3
+++ /dev/null
@@ -1,272 +0,0 @@
-.\"	$Vendor-Id: man.3,v 1.29 2011/01/03 11:31:26 kristaps Exp $
-.\"
-.\" Copyright (c) 2009-2010 Kristaps Dzonsons 
-.\"
-.\" Permission to use, copy, modify, and distribute this software for any
-.\" purpose with or without fee is hereby granted, provided that the above
-.\" copyright notice and this permission notice appear in all copies.
-.\"
-.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-.\"
-.Dd January 3, 2011
-.Dt MAN 3
-.Os
-.Sh NAME
-.Nm man ,
-.Nm man_alloc ,
-.Nm man_endparse ,
-.Nm man_free ,
-.Nm man_meta ,
-.Nm man_node ,
-.Nm man_parseln ,
-.Nm man_reset
-.Nd man macro compiler library
-.Sh SYNOPSIS
-.In mandoc.h
-.In man.h
-.Vt extern const char * const * man_macronames;
-.Ft int
-.Fo man_addspan
-.Fa "struct man *man"
-.Fa "const struct tbl_span *span"
-.Fc
-.Ft "struct man *"
-.Fo man_alloc
-.Fa "struct regset *regs"
-.Fa "void *data"
-.Fa "mandocmsg msgs"
-.Fc
-.Ft int
-.Fn man_endparse "struct man *man"
-.Ft void
-.Fn man_free "struct man *man"
-.Ft "const struct man_meta *"
-.Fn man_meta "const struct man *man"
-.Ft "const struct man_node *"
-.Fn man_node "const struct man *man"
-.Ft int
-.Fo man_parseln
-.Fa "struct man *man"
-.Fa "int line"
-.Fa "char *buf"
-.Fc
-.Ft void
-.Fn man_reset "struct man *man"
-.Sh DESCRIPTION
-The
-.Nm
-library parses lines of
-.Xr man 7
-input into an abstract syntax tree (AST).
-.Pp
-In general, applications initiate a parsing sequence with
-.Fn man_alloc ,
-parse each line in a document with
-.Fn man_parseln ,
-close the parsing session with
-.Fn man_endparse ,
-operate over the syntax tree returned by
-.Fn man_node
-and
-.Fn man_meta ,
-then free all allocated memory with
-.Fn man_free .
-The
-.Fn man_reset
-function may be used in order to reset the parser for another input
-sequence.
-.Pp
-Beyond the full set of macros defined in
-.Xr man 7 ,
-the
-.Nm
-library also accepts the following macro:
-.Pp
-.Bl -tag -width Ds -compact
-.It PD
-Has no effect.
-Handled as a current-scope line macro.
-.El
-.Ss Types
-.Bl -ohang
-.It Vt struct man
-An opaque type.
-Its values are only used privately within the library.
-.It Vt struct man_node
-A parsed node.
-See
-.Sx Abstract Syntax Tree
-for details.
-.El
-.Ss Functions
-If
-.Fn man_addspan ,
-.Fn man_parseln ,
-or
-.Fn man_endparse
-return 0, calls to any function but
-.Fn man_reset
-or
-.Fn man_free
-will raise an assertion.
-.Bl -ohang
-.It Fn man_addspan
-Add a table span to the parsing stream.
-Returns 0 on failure, 1 on success.
-.It Fn man_alloc
-Allocates a parsing structure.
-The
-.Fa data
-pointer is passed to
-.Fa msgs .
-Always returns a valid pointer.
-The pointer must be freed with
-.Fn man_free .
-.It Fn man_reset
-Reset the parser for another parse routine.
-After its use,
-.Fn man_parseln
-behaves as if invoked for the first time.
-.It Fn man_free
-Free all resources of a parser.
-The pointer is no longer valid after invocation.
-.It Fn man_parseln
-Parse a nil-terminated line of input.
-This line should not contain the trailing newline.
-Returns 0 on failure, 1 on success.
-The input buffer
-.Fa buf
-is modified by this function.
-.It Fn man_endparse
-Signals that the parse is complete.
-Returns 0 on failure, 1 on success.
-.It Fn man_node
-Returns the first node of the parse.
-.It Fn man_meta
-Returns the document's parsed meta-data.
-.El
-.Ss Variables
-The following variables are also defined:
-.Bl -ohang
-.It Va man_macronames
-An array of string-ified token names.
-.El
-.Ss Abstract Syntax Tree
-The
-.Nm
-functions produce an abstract syntax tree (AST) describing input in a
-regular form.
-It may be reviewed at any time with
-.Fn man_nodes ;
-however, if called before
-.Fn man_endparse ,
-or after
-.Fn man_endparse
-or
-.Fn man_parseln
-fail, it may be incomplete.
-.Pp
-This AST is governed by the ontological rules dictated in
-.Xr man 7
-and derives its terminology accordingly.
-.Pp
-The AST is composed of
-.Vt struct man_node
-nodes with element, root and text types as declared by the
-.Va type
-field.
-Each node also provides its parse point (the
-.Va line ,
-.Va sec ,
-and
-.Va pos
-fields), its position in the tree (the
-.Va parent ,
-.Va child ,
-.Va next
-and
-.Va prev
-fields) and some type-specific data.
-.Pp
-The tree itself is arranged according to the following normal form,
-where capitalised non-terminals represent nodes.
-.Pp
-.Bl -tag -width "ELEMENTXX" -compact
-.It ROOT
-\(<- mnode+
-.It mnode
-\(<- ELEMENT | TEXT | BLOCK
-.It BLOCK
-\(<- HEAD BODY
-.It HEAD
-\(<- mnode*
-.It BODY
-\(<- mnode*
-.It ELEMENT
-\(<- ELEMENT | TEXT*
-.It TEXT
-\(<- [[:alpha:]]*
-.El
-.Pp
-The only elements capable of nesting other elements are those with
-next-lint scope as documented in
-.Xr man 7 .
-.Sh EXAMPLES
-The following example reads lines from stdin and parses them, operating
-on the finished parse tree with
-.Fn parsed .
-This example does not error-check nor free memory upon failure.
-.Bd -literal -offset indent
-struct regset regs;
-struct man *man;
-struct man_node *node;
-char *buf;
-size_t len;
-int line;
-
-bzero(®s, sizeof(struct regset));
-line = 1;
-man = man_alloc(®s, NULL, NULL);
-buf = NULL;
-alloc_len = 0;
-
-while ((len = getline(&buf, &alloc_len, stdin)) >= 0) {
-    if (len && buflen[len - 1] = '\en')
-        buf[len - 1] = '\e0';
-    if ( ! man_parseln(man, line, buf))
-        errx(1, "man_parseln");
-    line++;
-}
-
-free(buf);
-
-if ( ! man_endparse(man))
-    errx(1, "man_endparse");
-if (NULL == (node = man_node(man)))
-    errx(1, "man_node");
-
-parsed(man, node);
-man_free(man);
-.Ed
-.Pp
-To compile this, execute
-.Pp
-.Dl % cc main.c libman.a libmandoc.a
-.Pp
-where
-.Pa main.c
-is the example file.
-.Sh SEE ALSO
-.Xr mandoc 1 ,
-.Xr man 7
-.Sh AUTHORS
-The
-.Nm
-library was written by
-.An Kristaps Dzonsons Aq kristaps@bsd.lv .
diff --git a/external/bsd/mdocml/dist/man.7 b/external/bsd/mdocml/dist/man.7
index 7d9ee19df..48f35b489 100644
--- a/external/bsd/mdocml/dist/man.7
+++ b/external/bsd/mdocml/dist/man.7
@@ -1,6 +1,7 @@
-.\"	$Vendor-Id: man.7,v 1.94 2011/01/04 23:32:21 kristaps Exp $
+.\"	$Vendor-Id: man.7,v 1.113 2012/01/03 15:16:24 kristaps Exp $
 .\"
-.\" Copyright (c) 2009, 2010 Kristaps Dzonsons 
+.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons 
+.\" Copyright (c) 2011 Ingo Schwarze 
 .\"
 .\" Permission to use, copy, modify, and distribute this software for any
 .\" purpose with or without fee is hereby granted, provided that the above
@@ -14,194 +15,68 @@
 .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\"
-.Dd January 4, 2011
+.Dd January 3, 2012
 .Dt MAN 7
 .Os
 .Sh NAME
 .Nm man
-.Nd man language reference
+.Nd legacy formatting language for manual pages
 .Sh DESCRIPTION
-The
+Traditionally, the
 .Nm man
-language was historically used to format
+language has been used to write
 .Ux
-manuals.
-This reference document describes its syntax, structure, and usage.
+manuals for the
+.Xr man 1
+utility.
+It supports limited control of presentational details like fonts,
+indentation and spacing.
+This reference document describes the structure of manual pages
+and the syntax and usage of the man language.
 .Pp
 .Bf -emphasis
 Do not use
 .Nm
-to write your manuals.
+to write your manuals:
 .Ef
+It lacks support for semantic markup.
 Use the
 .Xr mdoc 7
 language, instead.
 .Pp
-A
+In a
 .Nm
-document follows simple rules:  lines beginning with the control
-character
+document, lines beginning with the control character
 .Sq \&.
-are parsed for macros.
-Other lines are interpreted within the scope of
-prior macros:
+are called
+.Dq macro lines .
+The first word is the macro name.
+It usually consists of two capital letters.
+For a list of available macros, see
+.Sx MACRO OVERVIEW .
+The words following the macro name are arguments to the macro.
+.Pp
+Lines not beginning with the control character are called
+.Dq text lines .
+They provide free-form text to be printed; the formatting of the text
+depends on the respective processing context:
 .Bd -literal -offset indent
 \&.SH Macro lines change control state.
-Other lines are interpreted within the current state.
+Text lines are interpreted within the current state.
 .Ed
-.Sh INPUT ENCODING
-.Nm
-documents may contain only graphable 7-bit ASCII characters, the
-space character, and the tab character.
-All manuals must have
-.Ux
-line termination.
 .Pp
-Blank lines are acceptable; where found, the output will assert a
-vertical space.
-.Ss Comments
-Text following a
-.Sq \e\*q ,
-whether in a macro or free-form text line, is ignored to the end of
-line.
-A macro line with only a control character and comment escape,
-.Sq \&.\e\*q ,
-is also ignored.
-Macro lines with only a control character and optionally whitespace are
-stripped from input.
-.Ss Special Characters
-Special characters may occur in both macro and free-form lines.
-Sequences begin with the escape character
-.Sq \e
-followed by either an open-parenthesis
-.Sq \&(
-for two-character sequences; an open-bracket
-.Sq \&[
-for n-character sequences (terminated at a close-bracket
-.Sq \&] ) ;
-or a single one-character sequence.
-See
-.Xr mandoc_char 7
-for a complete list.
-Examples include
-.Sq \e(em
-.Pq em-dash
+Many aspects of the basic syntax of the
+.Nm
+language are based on the
+.Xr roff 7
+language; see the
+.Em LANGUAGE SYNTAX
 and
-.Sq \ee
-.Pq back-slash .
-.Ss Text Decoration
-Terms may be text-decorated using the
-.Sq \ef
-escape followed by an indicator: B (bold), I (italic), R (Roman), or P
-(revert to previous mode):
-.Pp
-.D1 \efBbold\efR \efIitalic\efP
-.Pp
-A numerical representation 3, 2, or 1 (bold, italic, and Roman,
-respectively) may be used instead.
-A text decoration is only valid, if specified in free-form text, until
-the next macro invocation; if specified within a macro, it's only valid
-until the macro closes scope.
-Note that macros like
-.Sx \&BR
-open and close a font scope with each argument.
-.Pp
-The
-.Sq \ef
-attribute is forgotten when entering or exiting a macro block.
-.Ss Whitespace
-Whitespace consists of the space character.
-In free-form lines, whitespace is preserved within a line; unescaped
-trailing spaces are stripped from input (unless in a literal context).
-Blank free-form lines, which may include spaces, are permitted and
-rendered as an empty line.
-.Pp
-In macro lines, whitespace delimits arguments and is discarded.
-If arguments are quoted, whitespace within the quotes is retained.
-.Ss Dates
-The
-.Sx \&TH
-macro is the only
-.Nm
-macro that requires a date.
-The form for this date is the ISO-8601
-standard
-.Cm YYYY-MM-DD .
-.Ss Scaling Widths
-Many macros support scaled widths for their arguments, such as
-stipulating a two-inch paragraph indentation with the following:
-.Bd -literal -offset indent
-\&.HP 2i
-.Ed
-.Pp
-The syntax for scaled widths is
-.Sq Li [+-]?[0-9]*.[0-9]*[:unit:]? ,
-where a decimal must be preceded or proceeded by at least one digit.
-Negative numbers, while accepted, are truncated to zero.
-The following scaling units are accepted:
-.Pp
-.Bl -tag -width Ds -offset indent -compact
-.It c
-centimetre
-.It i
-inch
-.It P
-pica (~1/6 inch)
-.It p
-point (~1/72 inch)
-.It f
-synonym for
-.Sq u
-.It v
-default vertical span
-.It m
-width of rendered
-.Sq m
-.Pq em
-character
-.It n
-width of rendered
-.Sq n
-.Pq en
-character
-.It u
-default horizontal span
-.It M
-mini-em (~1/100 em)
-.El
-.Pp
-Using anything other than
-.Sq m ,
-.Sq n ,
-.Sq u ,
-or
-.Sq v
-is necessarily non-portable across output media.
-.Pp
-If a scaling unit is not provided, the numerical value is interpreted
-under the default rules of
-.Sq v
-for vertical spaces and
-.Sq u
-for horizontal ones.
-.Em Note :
-this differs from
-.Xr mdoc 7 ,
-which, if a unit is not provided, will instead interpret the string as
-literal text.
-.Ss Sentence Spacing
-When composing a manual, make sure that sentences end at the end of
-a line.
-By doing so, front-ends will be able to apply the proper amount of
-spacing after the end of sentence (unescaped) period, exclamation mark,
-or question mark followed by zero or more non-sentence closing
-delimiters
-.Po
-.Sq \&) ,
-.Sq \&] ,
-.Sq \&' ,
-.Sq \&"
-.Pc .
+.Em MACRO SYNTAX
+sections in the
+.Xr roff 7
+manual for details, in particular regarding
+comments, escape sequences, whitespace, and quoting.
 .Sh MANUAL STRUCTURE
 Each
 .Nm
@@ -213,42 +88,46 @@ appears as the first macro.
 .Pp
 Beyond
 .Sx \&TH ,
-at least one macro or text node must appear in the document.
-Documents are generally structured as follows:
+at least one macro or text line must appear in the document.
+.Pp
+The following is a well-formed skeleton
+.Nm
+file for a utility
+.Qq progname :
 .Bd -literal -offset indent
-\&.TH FOO 1 2009-10-10
+\&.TH PROGNAME 1 2009-10-10
 \&.SH NAME
-\efBfoo\efR \e(en a description goes here
-\&.\e\*q .SH LIBRARY
-\&.\e\*q For sections 2 & 3 only.
-\&.\e\*q Not used in OpenBSD.
+\efBprogname\efR \e(en a description goes here
+\&.\e\(dq .SH LIBRARY
+\&.\e\(dq For sections 2 & 3 only.
+\&.\e\(dq Not used in OpenBSD.
 \&.SH SYNOPSIS
-\efBfoo\efR [\efB\e-options\efR] arguments...
+\efBprogname\efR [\efB\e-options\efR] arguments...
 \&.SH DESCRIPTION
 The \efBfoo\efR utility processes files...
-\&.\e\*q .SH IMPLEMENTATION NOTES
-\&.\e\*q Not used in OpenBSD.
-\&.\e\*q .SH RETURN VALUES
-\&.\e\*q For sections 2, 3, & 9 only.
-\&.\e\*q .SH ENVIRONMENT
-\&.\e\*q For sections 1, 6, 7, & 8 only.
-\&.\e\*q .SH FILES
-\&.\e\*q .SH EXIT STATUS
-\&.\e\*q For sections 1, 6, & 8 only.
-\&.\e\*q .SH EXAMPLES
-\&.\e\*q .SH DIAGNOSTICS
-\&.\e\*q For sections 1, 4, 6, 7, & 8 only.
-\&.\e\*q .SH ERRORS
-\&.\e\*q For sections 2, 3, & 9 only.
-\&.\e\*q .SH SEE ALSO
-\&.\e\*q .BR foo ( 1 )
-\&.\e\*q .SH STANDARDS
-\&.\e\*q .SH HISTORY
-\&.\e\*q .SH AUTHORS
-\&.\e\*q .SH CAVEATS
-\&.\e\*q .SH BUGS
-\&.\e\*q .SH SECURITY CONSIDERATIONS
-\&.\e\*q Not used in OpenBSD.
+\&.\e\(dq .SH IMPLEMENTATION NOTES
+\&.\e\(dq Not used in OpenBSD.
+\&.\e\(dq .SH RETURN VALUES
+\&.\e\(dq For sections 2, 3, & 9 only.
+\&.\e\(dq .SH ENVIRONMENT
+\&.\e\(dq For sections 1, 6, 7, & 8 only.
+\&.\e\(dq .SH FILES
+\&.\e\(dq .SH EXIT STATUS
+\&.\e\(dq For sections 1, 6, & 8 only.
+\&.\e\(dq .SH EXAMPLES
+\&.\e\(dq .SH DIAGNOSTICS
+\&.\e\(dq For sections 1, 4, 6, 7, & 8 only.
+\&.\e\(dq .SH ERRORS
+\&.\e\(dq For sections 2, 3, & 9 only.
+\&.\e\(dq .SH SEE ALSO
+\&.\e\(dq .BR foo ( 1 )
+\&.\e\(dq .SH STANDARDS
+\&.\e\(dq .SH HISTORY
+\&.\e\(dq .SH AUTHORS
+\&.\e\(dq .SH CAVEATS
+\&.\e\(dq .SH BUGS
+\&.\e\(dq .SH SECURITY CONSIDERATIONS
+\&.\e\(dq Not used in OpenBSD.
 .Ed
 .Pp
 The sections in a
@@ -354,146 +233,50 @@ in this section.
 .It Em SECURITY CONSIDERATIONS
 Documents any security precautions that operators should consider.
 .El
-.Sh MACRO SYNTAX
-Macros are one to three characters in length and begin with a
-control character,
-.Sq \&. ,
-at the beginning of the line.
-The
-.Sq \(aq
-macro control character is also accepted.
-An arbitrary amount of whitespace (spaces or tabs) may sit between the
-control character and the macro name.
-Thus, the following are equivalent:
-.Bd -literal -offset indent
-\&.PP
-\&.\ \ \ PP
-.Ed
-.Pp
-The
-.Nm
-macros are classified by scope: line scope or block scope.
-Line macros are only scoped to the current line (and, in some
-situations, the subsequent line).
-Block macros are scoped to the current line and subsequent lines until
-closed by another block macro.
-.Ss Line Macros
-Line macros are generally scoped to the current line, with the body
-consisting of zero or more arguments.
-If a macro is scoped to the next line and the line arguments are empty,
-the next line, which must be text, is used instead.
-Thus:
-.Bd -literal -offset indent
-\&.I
-foo
-.Ed
-.Pp
-is equivalent to
-.Sq \&.I foo .
-If next-line macros are invoked consecutively, only the last is used.
-If a next-line macro is followed by a non-next-line macro, an error is
-raised, except for
-.Sx \&br ,
-.Sx \&sp ,
-and
-.Sx \&na .
-.Pp
-The syntax is as follows:
-.Bd -literal -offset indent
-\&.YO \(lBbody...\(rB
-\(lBbody...\(rB
-.Ed
-.Pp
-.Bl -column -compact -offset indent "MacroX" "ArgumentsX" "ScopeXXXXX" "CompatX"
-.It Em Macro Ta Em Arguments Ta Em Scope     Ta Em Notes
-.It Sx \&AT  Ta    <=1       Ta    current   Ta    \&
-.It Sx \&B   Ta    n         Ta    next-line Ta    \&
-.It Sx \&BI  Ta    n         Ta    current   Ta    \&
-.It Sx \&BR  Ta    n         Ta    current   Ta    \&
-.It Sx \&DT  Ta    0         Ta    current   Ta    \&
-.It Sx \&I   Ta    n         Ta    next-line Ta    \&
-.It Sx \&IB  Ta    n         Ta    current   Ta    \&
-.It Sx \&IR  Ta    n         Ta    current   Ta    \&
-.It Sx \&R   Ta    n         Ta    next-line Ta    \&
-.It Sx \&RB  Ta    n         Ta    current   Ta    \&
-.It Sx \&RI  Ta    n         Ta    current   Ta    \&
-.It Sx \&SB  Ta    n         Ta    next-line Ta    \&
-.It Sx \&SM  Ta    n         Ta    next-line Ta    \&
-.It Sx \&TH  Ta    >1, <6    Ta    current   Ta    \&
-.It Sx \&UC  Ta    <=1       Ta    current   Ta    \&
-.It Sx \&br  Ta    0         Ta    current   Ta    compat
-.It Sx \&fi  Ta    0         Ta    current   Ta    compat
-.It Sx \&ft  Ta    1         Ta    current   Ta    compat
-.It Sx \&in  Ta    1         Ta    current   Ta    compat
-.It Sx \&na  Ta    0         Ta    current   Ta    compat
-.It Sx \&nf  Ta    0         Ta    current   Ta    compat
-.It Sx \&sp  Ta    1         Ta    current   Ta    compat
+.Sh MACRO OVERVIEW
+This overview is sorted such that macros of similar purpose are listed
+together, to help find the best macro for any given purpose.
+Deprecated macros are not included in the overview, but can be found
+in the alphabetical reference below.
+.Ss Page header and footer meta-data
+.Bl -column "PP, LP, P" description
+.It Sx TH Ta set the title: Ar title section date Op Ar source Op Ar volume
+.It Sx AT Ta display AT&T UNIX version in the page footer (<= 1 argument)
+.It Sx UC Ta display BSD version in the page footer (<= 1 argument)
 .El
-.Pp
-Macros marked as
-.Qq compat
-are included for compatibility with the significant corpus of existing
-manuals that mix dialects of roff.
-These macros should not be used for portable
-.Nm
-manuals.
-.Ss Block Macros
-Block macros comprise a head and body.
-As with in-line macros, the head is scoped to the current line and, in
-one circumstance, the next line (the next-line stipulations as in
-.Sx Line Macros
-apply here as well).
-.Pp
-The syntax is as follows:
-.Bd -literal -offset indent
-\&.YO \(lBhead...\(rB
-\(lBhead...\(rB
-\(lBbody...\(rB
-.Ed
-.Pp
-The closure of body scope may be to the section, where a macro is closed
-by
-.Sx \&SH ;
-sub-section, closed by a section or
-.Sx \&SS ;
-part, closed by a section, sub-section, or
-.Sx \&RE ;
-or paragraph, closed by a section, sub-section, part,
-.Sx \&HP ,
-.Sx \&IP ,
-.Sx \&LP ,
-.Sx \&P ,
-.Sx \&PP ,
-or
-.Sx \&TP .
-No closure refers to an explicit block closing macro.
-.Pp
-As a rule, block macros may not be nested; thus, calling a block macro
-while another block macro scope is open, and the open scope is not
-implicitly closed, is syntactically incorrect.
-.Pp
-.Bl -column -compact -offset indent "MacroX" "ArgumentsX" "Head ScopeX" "sub-sectionX" "compatX"
-.It Em Macro Ta Em Arguments Ta Em Head Scope Ta Em Body Scope  Ta Em Notes
-.It Sx \&HP  Ta    <2        Ta    current    Ta    paragraph   Ta    \&
-.It Sx \&IP  Ta    <3        Ta    current    Ta    paragraph   Ta    \&
-.It Sx \&LP  Ta    0         Ta    current    Ta    paragraph   Ta    \&
-.It Sx \&P   Ta    0         Ta    current    Ta    paragraph   Ta    \&
-.It Sx \&PP  Ta    0         Ta    current    Ta    paragraph   Ta    \&
-.It Sx \&RE  Ta    0         Ta    current    Ta    none        Ta    compat
-.It Sx \&RS  Ta    1         Ta    current    Ta    part        Ta    compat
-.It Sx \&SH  Ta    >0        Ta    next-line  Ta    section     Ta    \&
-.It Sx \&SS  Ta    >0        Ta    next-line  Ta    sub-section Ta    \&
-.It Sx \&TP  Ta    n         Ta    next-line  Ta    paragraph   Ta    \&
+.Ss Sections and paragraphs
+.Bl -column "PP, LP, P" description
+.It Sx SH Ta section header (one line)
+.It Sx SS Ta subsection header (one line)
+.It Sx PP , LP , P Ta start an undecorated paragraph (no arguments)
+.It Sx RS , RE Ta reset the left margin: Op Ar width
+.It Sx IP Ta indented paragraph: Op Ar head Op Ar width
+.It Sx TP Ta tagged paragraph: Op Ar width
+.It Sx HP Ta hanged paragraph: Op Ar width
+.It Sx \&br Ta force output line break in text mode (no arguments)
+.It Sx \&sp Ta force vertical space: Op Ar height
+.It Sx fi , nf Ta fill mode and no-fill mode (no arguments)
+.It Sx in Ta additional indent: Op Ar width
 .El
-.Pp
-Macros marked
-.Qq compat
-are as mentioned in
-.Sx Line Macros .
-.Pp
-If a block macro is next-line scoped, it may only be followed by in-line
-macros for decorating text.
-.Sh REFERENCE
+.Ss Physical markup
+.Bl -column "PP, LP, P" description
+.It Sx B Ta boldface font
+.It Sx I Ta italic font
+.It Sx R Ta roman (default) font
+.It Sx SB Ta small boldface font
+.It Sx SM Ta small roman font
+.It Sx BI Ta alternate between boldface and italic fonts
+.It Sx BR Ta alternate between boldface and roman fonts
+.It Sx IB Ta alternate between italic and boldface fonts
+.It Sx IR Ta alternate between italic and roman fonts
+.It Sx RB Ta alternate between roman and boldface fonts
+.It Sx RI Ta alternate between roman and italic fonts
+.El
+.Ss Semantic markup
+.Bl -column "PP, LP, P" description
+.It Sx OP Ta optional arguments
+.El
+.Sh MACRO REFERENCE
 This section is a canonical reference to all macros, arranged
 alphabetically.
 For the scoping of individual macros, see
@@ -658,6 +441,19 @@ See also
 .Sx \&PP ,
 and
 .Sx \&TP .
+.Ss \&OP
+Optional command-line argument.
+This has the following syntax:
+.Bd -filled -offset indent
+.Pf \. Sx \&OP
+.Cm key Op Cm value
+.Ed
+.Pp
+The
+.Cm key
+is usually a command-line flag and
+.Cm value
+its argument.
 .Ss \&P
 Synonym for
 .Sx \&LP .
@@ -705,6 +501,9 @@ and
 .Ss \&RE
 Explicitly close out the scope of a prior
 .Sx \&RS .
+The default left margin is restored to the state of the original
+.Sx \&RS
+invocation.
 .Ss \&RI
 Text is rendered alternately in roman (the default font) and italics.
 Whitespace between arguments is omitted in output.
@@ -721,13 +520,10 @@ See also
 and
 .Sx \&IR .
 .Ss \&RS
-Begin a part setting the left margin.
-The left margin controls the offset, following an initial indentation,
-to un-indented text such as that of
-.Sx \&PP .
+Temporarily reset the default left margin.
 This has the following syntax:
 .Bd -filled -offset indent
-.Pf \. Sx \&Rs
+.Pf \. Sx \&RS
 .Op Cm width
 .Ed
 .Pp
@@ -736,6 +532,9 @@ The
 argument must conform to
 .Sx Scaling Widths .
 If not specified, the saved or default width is used.
+.Pp
+See also
+.Sx \&RE .
 .Ss \&SB
 Text is rendered in small size (one point smaller than the default font)
 bold face.
@@ -756,26 +555,27 @@ The paragraph left-margin width is reset to the default.
 Sets the title of the manual page with the following syntax:
 .Bd -filled -offset indent
 .Pf \. Sx \&TH
-.Cm title section
-.Op Cm date Op Cm source Op Cm volume
+.Ar title section date
+.Op Ar source Op Ar volume
 .Ed
 .Pp
-At least the upper-case document
-.Cm title
-and the manual
-.Cm section
-arguments must be provided.
-The
-.Cm date
-argument should be formatted as described in
-.Sx Dates ,
-but will be printed verbatim if it is not.
-If the date is not specified, the current date is used.
-The
-.Cm source
+Conventionally, the document
+.Ar title
+is given in all caps.
+The recommended
+.Ar date
+format is
+.Sy YYYY-MM-DD
+as specified in the ISO-8601 standard;
+if the argument does not conform, it is printed verbatim.
+If the
+.Ar date
+is empty or not specified, the current date is used.
+The optional
+.Ar source
 string specifies the organisation providing the utility.
 The
-.Cm volume
+.Ar volume
 string replaces the default rendered volume, which is dictated by the
 manual section.
 .Pp
@@ -842,6 +642,10 @@ Begin literal mode: all subsequent free-form lines have their end of
 line boundaries preserved.
 May be ended by
 .Sx \&fi .
+Literal mode is implicitly ended by
+.Sx \&SH
+or
+.Sx \&SS .
 .Ss \&sp
 Insert vertical spaces into output with the following syntax:
 .Bd -filled -offset indent
@@ -860,6 +664,144 @@ Defaults to 1, if unspecified.
 .Pp
 See also
 .Sx \&br .
+.Sh MACRO SYNTAX
+The
+.Nm
+macros are classified by scope: line scope or block scope.
+Line macros are only scoped to the current line (and, in some
+situations, the subsequent line).
+Block macros are scoped to the current line and subsequent lines until
+closed by another block macro.
+.Ss Line Macros
+Line macros are generally scoped to the current line, with the body
+consisting of zero or more arguments.
+If a macro is scoped to the next line and the line arguments are empty,
+the next line, which must be text, is used instead.
+Thus:
+.Bd -literal -offset indent
+\&.I
+foo
+.Ed
+.Pp
+is equivalent to
+.Sq \&.I foo .
+If next-line macros are invoked consecutively, only the last is used.
+If a next-line macro is followed by a non-next-line macro, an error is
+raised, except for
+.Sx \&br ,
+.Sx \&sp ,
+and
+.Sx \&na .
+.Pp
+The syntax is as follows:
+.Bd -literal -offset indent
+\&.YO \(lBbody...\(rB
+\(lBbody...\(rB
+.Ed
+.Bl -column "MacroX" "ArgumentsX" "ScopeXXXXX" "CompatX" -offset indent
+.It Em Macro Ta Em Arguments Ta Em Scope     Ta Em Notes
+.It Sx \&AT  Ta    <=1       Ta    current   Ta    \&
+.It Sx \&B   Ta    n         Ta    next-line Ta    \&
+.It Sx \&BI  Ta    n         Ta    current   Ta    \&
+.It Sx \&BR  Ta    n         Ta    current   Ta    \&
+.It Sx \&DT  Ta    0         Ta    current   Ta    \&
+.It Sx \&I   Ta    n         Ta    next-line Ta    \&
+.It Sx \&IB  Ta    n         Ta    current   Ta    \&
+.It Sx \&IR  Ta    n         Ta    current   Ta    \&
+.It Sx \&OP  Ta    0, 1      Ta    current   Ta    compat
+.It Sx \&R   Ta    n         Ta    next-line Ta    \&
+.It Sx \&RB  Ta    n         Ta    current   Ta    \&
+.It Sx \&RI  Ta    n         Ta    current   Ta    \&
+.It Sx \&SB  Ta    n         Ta    next-line Ta    \&
+.It Sx \&SM  Ta    n         Ta    next-line Ta    \&
+.It Sx \&TH  Ta    >1, <6    Ta    current   Ta    \&
+.It Sx \&UC  Ta    <=1       Ta    current   Ta    \&
+.It Sx \&br  Ta    0         Ta    current   Ta    compat
+.It Sx \&fi  Ta    0         Ta    current   Ta    compat
+.It Sx \&ft  Ta    1         Ta    current   Ta    compat
+.It Sx \&in  Ta    1         Ta    current   Ta    compat
+.It Sx \&na  Ta    0         Ta    current   Ta    compat
+.It Sx \&nf  Ta    0         Ta    current   Ta    compat
+.It Sx \&sp  Ta    1         Ta    current   Ta    compat
+.El
+.Pp
+Macros marked as
+.Qq compat
+are included for compatibility with the significant corpus of existing
+manuals that mix dialects of roff.
+These macros should not be used for portable
+.Nm
+manuals.
+.Ss Block Macros
+Block macros comprise a head and body.
+As with in-line macros, the head is scoped to the current line and, in
+one circumstance, the next line (the next-line stipulations as in
+.Sx Line Macros
+apply here as well).
+.Pp
+The syntax is as follows:
+.Bd -literal -offset indent
+\&.YO \(lBhead...\(rB
+\(lBhead...\(rB
+\(lBbody...\(rB
+.Ed
+.Pp
+The closure of body scope may be to the section, where a macro is closed
+by
+.Sx \&SH ;
+sub-section, closed by a section or
+.Sx \&SS ;
+part, closed by a section, sub-section, or
+.Sx \&RE ;
+or paragraph, closed by a section, sub-section, part,
+.Sx \&HP ,
+.Sx \&IP ,
+.Sx \&LP ,
+.Sx \&P ,
+.Sx \&PP ,
+or
+.Sx \&TP .
+No closure refers to an explicit block closing macro.
+.Pp
+As a rule, block macros may not be nested; thus, calling a block macro
+while another block macro scope is open, and the open scope is not
+implicitly closed, is syntactically incorrect.
+.Bl -column "MacroX" "ArgumentsX" "Head ScopeX" "sub-sectionX" "compatX" -offset indent
+.It Em Macro Ta Em Arguments Ta Em Head Scope Ta Em Body Scope  Ta Em Notes
+.It Sx \&HP  Ta    <2        Ta    current    Ta    paragraph   Ta    \&
+.It Sx \&IP  Ta    <3        Ta    current    Ta    paragraph   Ta    \&
+.It Sx \&LP  Ta    0         Ta    current    Ta    paragraph   Ta    \&
+.It Sx \&P   Ta    0         Ta    current    Ta    paragraph   Ta    \&
+.It Sx \&PP  Ta    0         Ta    current    Ta    paragraph   Ta    \&
+.It Sx \&RE  Ta    0         Ta    current    Ta    none        Ta    compat
+.It Sx \&RS  Ta    1         Ta    current    Ta    part        Ta    compat
+.It Sx \&SH  Ta    >0        Ta    next-line  Ta    section     Ta    \&
+.It Sx \&SS  Ta    >0        Ta    next-line  Ta    sub-section Ta    \&
+.It Sx \&TP  Ta    n         Ta    next-line  Ta    paragraph   Ta    \&
+.El
+.Pp
+Macros marked
+.Qq compat
+are as mentioned in
+.Sx Line Macros .
+.Pp
+If a block macro is next-line scoped, it may only be followed by in-line
+macros for decorating text.
+.Ss Font handling
+In
+.Nm
+documents, both
+.Sx Physical markup
+macros and
+.Xr roff 7
+.Ql \ef
+font escape sequences can be used to choose fonts.
+In text lines, the effect of manual font selection by escape sequences
+only lasts until the next macro invocation; in macro lines, it only lasts
+until the end of the macro scope.
+Note that macros like
+.Sx \&BR
+open and close a font scope for each argument.
 .Sh COMPATIBILITY
 This section documents areas of questionable portability between
 implementations of the
@@ -868,6 +810,14 @@ language.
 .Pp
 .Bl -dash -compact
 .It
+Do not depend on
+.Sx \&SH
+or
+.Sx \&SS
+to close out a literal context opened with
+.Sx \&nf .
+This behaviour may not be portable.
+.It
 In quoted literals, GNU troff allowed pair-wise double-quotes to produce
 a standalone double-quote in formatted output.
 It is not known whether this behaviour is exhibited by other formatters.
@@ -908,10 +858,30 @@ The
 .Sx \&sp
 macro does not accept negative values in mandoc.
 In GNU troff, this would result in strange behaviour.
+.It
+In page header lines, GNU troff versions up to and including 1.21
+only print
+.Ar volume
+names explicitly specified in the
+.Sx \&TH
+macro; mandoc and newer groff print the default volume name
+corresponding to the
+.Ar section
+number when no
+.Ar volume
+is given, like in
+.Xr mdoc 7 .
 .El
+.Pp
+The
+.Sx OP
+macro is part of the extended
+.Nm
+macro set, and may not be portable to non-GNU troff implementations.
 .Sh SEE ALSO
 .Xr man 1 ,
 .Xr mandoc 1 ,
+.Xr eqn 7 ,
 .Xr mandoc_char 7 ,
 .Xr mdoc 7 ,
 .Xr roff 7 ,
@@ -923,6 +893,9 @@ language first appeared as a macro package for the roff typesetting
 system in
 .At v7 .
 It was later rewritten by James Clark as a macro package for groff.
+Eric S. Raymond wrote the extended
+.Nm
+macros for groff in 2007.
 The stand-alone implementation that is part of the
 .Xr mandoc 1
 utility written by Kristaps Dzonsons appeared in
@@ -931,7 +904,8 @@ utility written by Kristaps Dzonsons appeared in
 This
 .Nm
 reference was written by
-.An Kristaps Dzonsons Aq kristaps@bsd.lv .
+.An Kristaps Dzonsons ,
+.Mt kristaps@bsd.lv .
 .Sh CAVEATS
 Do not use this language.
 Use
diff --git a/external/bsd/mdocml/dist/man.c b/external/bsd/mdocml/dist/man.c
index 0700dee42..7d474868a 100644
--- a/external/bsd/mdocml/dist/man.c
+++ b/external/bsd/mdocml/dist/man.c
@@ -1,6 +1,6 @@
-/*	$Vendor-Id: man.c,v 1.96 2011/01/03 11:31:26 kristaps Exp $ */
+/*	$Vendor-Id: man.c,v 1.115 2012/01/03 15:16:24 kristaps Exp $ */
 /*
- * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons 
+ * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons 
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -26,6 +26,7 @@
 #include 
 #include 
 
+#include "man.h"
 #include "mandoc.h"
 #include "libman.h"
 #include "libmandoc.h"
@@ -39,17 +40,15 @@ const	char *const __man_macronames[MAN_MAX] = {
 	"RI",		"na",		"sp",		"nf",
 	"fi",		"RE",		"RS",		"DT",
 	"UC",		"PD",		"AT",		"in",
-	"ft"
+	"ft",		"OP"
 	};
 
 const	char * const *man_macronames = __man_macronames;
 
-static	struct man_node	*man_node_alloc(int, int, 
+static	struct man_node	*man_node_alloc(struct man *, int, int, 
 				enum man_type, enum mant);
 static	int		 man_node_append(struct man *, 
 				struct man_node *);
-static	int		 man_span_alloc(struct man *, 
-				const struct tbl_span *);
 static	void		 man_node_free(struct man_node *);
 static	void		 man_node_unlink(struct man *, 
 				struct man_node *);
@@ -97,16 +96,15 @@ man_free(struct man *man)
 
 
 struct man *
-man_alloc(struct regset *regs, void *data, mandocmsg msg)
+man_alloc(struct roff *roff, struct mparse *parse)
 {
 	struct man	*p;
 
 	p = mandoc_calloc(1, sizeof(struct man));
 
 	man_hash_init();
-	p->data = data;
-	p->msg = msg;
-	p->regs = regs;
+	p->parse = parse;
+	p->roff = roff;
 
 	man_alloc1(p);
 	return(p);
@@ -129,8 +127,11 @@ int
 man_parseln(struct man *m, int ln, char *buf, int offs)
 {
 
+	m->flags |= MAN_NEWLINE;
+
 	assert( ! (MAN_HALT & m->flags));
-	return(('.' == buf[offs] || '\'' == buf[offs]) ? 
+
+	return (mandoc_getcontrol(buf, &offs) ?
 			man_pmacro(m, ln, buf, offs) : 
 			man_ptext(m, ln, buf, offs));
 }
@@ -146,8 +147,8 @@ man_free1(struct man *man)
 		free(man->meta.title);
 	if (man->meta.source)
 		free(man->meta.source);
-	if (man->meta.rawdate)
-		free(man->meta.rawdate);
+	if (man->meta.date)
+		free(man->meta.date);
 	if (man->meta.vol)
 		free(man->meta.vol);
 	if (man->meta.msec)
@@ -203,6 +204,10 @@ man_node_append(struct man *man, struct man_node *p)
 		assert(MAN_BLOCK == p->parent->type);
 		p->parent->head = p;
 		break;
+	case (MAN_TAIL):
+		assert(MAN_BLOCK == p->parent->type);
+		p->parent->tail = p;
+		break;
 	case (MAN_BODY):
 		assert(MAN_BLOCK == p->parent->type);
 		p->parent->body = p;
@@ -229,7 +234,8 @@ man_node_append(struct man *man, struct man_node *p)
 
 
 static struct man_node *
-man_node_alloc(int line, int pos, enum man_type type, enum mant tok)
+man_node_alloc(struct man *m, int line, int pos, 
+		enum man_type type, enum mant tok)
 {
 	struct man_node *p;
 
@@ -238,6 +244,10 @@ man_node_alloc(int line, int pos, enum man_type type, enum mant tok)
 	p->pos = pos;
 	p->type = type;
 	p->tok = tok;
+
+	if (MAN_NEWLINE & m->flags)
+		p->flags |= MAN_LINE;
+	m->flags &= ~MAN_NEWLINE;
 	return(p);
 }
 
@@ -247,7 +257,20 @@ man_elem_alloc(struct man *m, int line, int pos, enum mant tok)
 {
 	struct man_node *p;
 
-	p = man_node_alloc(line, pos, MAN_ELEM, tok);
+	p = man_node_alloc(m, line, pos, MAN_ELEM, tok);
+	if ( ! man_node_append(m, p))
+		return(0);
+	m->next = MAN_NEXT_CHILD;
+	return(1);
+}
+
+
+int
+man_tail_alloc(struct man *m, int line, int pos, enum mant tok)
+{
+	struct man_node *p;
+
+	p = man_node_alloc(m, line, pos, MAN_TAIL, tok);
 	if ( ! man_node_append(m, p))
 		return(0);
 	m->next = MAN_NEXT_CHILD;
@@ -260,7 +283,7 @@ man_head_alloc(struct man *m, int line, int pos, enum mant tok)
 {
 	struct man_node *p;
 
-	p = man_node_alloc(line, pos, MAN_HEAD, tok);
+	p = man_node_alloc(m, line, pos, MAN_HEAD, tok);
 	if ( ! man_node_append(m, p))
 		return(0);
 	m->next = MAN_NEXT_CHILD;
@@ -273,7 +296,7 @@ man_body_alloc(struct man *m, int line, int pos, enum mant tok)
 {
 	struct man_node *p;
 
-	p = man_node_alloc(line, pos, MAN_BODY, tok);
+	p = man_node_alloc(m, line, pos, MAN_BODY, tok);
 	if ( ! man_node_append(m, p))
 		return(0);
 	m->next = MAN_NEXT_CHILD;
@@ -286,43 +309,20 @@ man_block_alloc(struct man *m, int line, int pos, enum mant tok)
 {
 	struct man_node *p;
 
-	p = man_node_alloc(line, pos, MAN_BLOCK, tok);
+	p = man_node_alloc(m, line, pos, MAN_BLOCK, tok);
 	if ( ! man_node_append(m, p))
 		return(0);
 	m->next = MAN_NEXT_CHILD;
 	return(1);
 }
 
-static int
-man_span_alloc(struct man *m, const struct tbl_span *span)
-{
-	struct man_node	*n;
-
-	/* FIXME: grab from span */
-	n = man_node_alloc(0, 0, MAN_TBL, MAN_MAX);
-	n->span = span;
-
-	if ( ! man_node_append(m, n))
-		return(0);
-
-	m->next = MAN_NEXT_SIBLING;
-	return(1);
-}
-
 int
 man_word_alloc(struct man *m, int line, int pos, const char *word)
 {
 	struct man_node	*n;
-	size_t		 sv, len;
 
-	len = strlen(word);
-
-	n = man_node_alloc(line, pos, MAN_TEXT, MAN_MAX);
-	n->string = mandoc_malloc(len + 1);
-	sv = strlcpy(n->string, word, len + 1);
-
-	/* Prohibit truncation. */
-	assert(sv < len + 1);
+	n = man_node_alloc(m, line, pos, MAN_TEXT, MAN_MAX);
+	n->string = roff_strdup(m->roff, word);
 
 	if ( ! man_node_append(m, n))
 		return(0);
@@ -357,15 +357,38 @@ man_node_delete(struct man *m, struct man_node *p)
 	man_node_free(p);
 }
 
+int
+man_addeqn(struct man *m, const struct eqn *ep)
+{
+	struct man_node	*n;
+
+	assert( ! (MAN_HALT & m->flags));
+
+	n = man_node_alloc(m, ep->ln, ep->pos, MAN_EQN, MAN_MAX);
+	n->eqn = ep;
+
+	if ( ! man_node_append(m, n))
+		return(0);
+
+	m->next = MAN_NEXT_SIBLING;
+	return(man_descope(m, ep->ln, ep->pos));
+}
 
 int
 man_addspan(struct man *m, const struct tbl_span *sp)
 {
+	struct man_node	*n;
 
 	assert( ! (MAN_HALT & m->flags));
-	if ( ! man_span_alloc(m, sp))
+
+	n = man_node_alloc(m, sp->line, 0, MAN_TBL, MAN_MAX);
+	n->span = sp;
+
+	if ( ! man_node_append(m, n))
 		return(0);
-	return(man_descope(m, 0, 0));
+
+	m->next = MAN_NEXT_SIBLING;
+	return(man_descope(m, sp->line, 0));
 }
 
 static int
@@ -392,21 +415,11 @@ man_descope(struct man *m, int line, int offs)
 	return(man_body_alloc(m, line, offs, m->last->tok));
 }
 
-
 static int
 man_ptext(struct man *m, int line, char *buf, int offs)
 {
 	int		 i;
 
-	/* Ignore bogus comments. */
-
-	if ('\\' == buf[offs] && 
-			'.' == buf[offs + 1] && 
-			'"' == buf[offs + 2]) {
-		man_pmsg(m, line, offs, MANDOCERR_BADCOMMENT);
-		return(1);
-	}
-
 	/* Literal free-form text whitespace is preserved. */
 
 	if (MAN_LITERAL & m->flags) {
@@ -464,67 +477,54 @@ man_ptext(struct man *m, int line, char *buf, int offs)
 	return(man_descope(m, line, offs));
 }
 
-
 static int
 man_pmacro(struct man *m, int ln, char *buf, int offs)
 {
-	int		 i, j, ppos;
+	int		 i, ppos;
 	enum mant	 tok;
 	char		 mac[5];
 	struct man_node	*n;
 
-	/* Comments and empties are quickly ignored. */
-
-	offs++;
-
-	if ('\0' == buf[offs])
+	if ('"' == buf[offs]) {
+		man_pmsg(m, ln, offs, MANDOCERR_BADCOMMENT);
+		return(1);
+	} else if ('\0' == buf[offs])
 		return(1);
 
-	i = offs;
-
-	/*
-	 * Skip whitespace between the control character and initial
-	 * text.  "Whitespace" is both spaces and tabs.
-	 */
-
-	if (' ' == buf[i] || '\t' == buf[i]) {
-		i++;
-		while (buf[i] && (' ' == buf[i] || '\t' == buf[i]))
-			i++;
-		if ('\0' == buf[i])
-			goto out;
-	}
-
-	ppos = i;
+	ppos = offs;
 
 	/*
 	 * Copy the first word into a nil-terminated buffer.
 	 * Stop copying when a tab, space, or eoln is encountered.
 	 */
 
-	j = 0;
-	while (j < 4 && '\0' != buf[i] && ' ' != buf[i] && '\t' != buf[i])
-		mac[j++] = buf[i++];
-	mac[j] = '\0';
+	i = 0;
+	while (i < 4 && '\0' != buf[offs] && 
+			' ' != buf[offs] && '\t' != buf[offs])
+		mac[i++] = buf[offs++];
+
+	mac[i] = '\0';
+
+	tok = (i > 0 && i < 4) ? man_hash_find(mac) : MAN_MAX;
 
-	tok = (j > 0 && j < 4) ? man_hash_find(mac) : MAN_MAX;
 	if (MAN_MAX == tok) {
-		man_vmsg(m, MANDOCERR_MACRO, ln, ppos, "%s", buf + ppos - 1);
+		mandoc_vmsg(MANDOCERR_MACRO, m->parse, ln, 
+				ppos, "%s", buf + ppos - 1);
 		return(1);
 	}
 
 	/* The macro is sane.  Jump to the next word. */
 
-	while (buf[i] && ' ' == buf[i])
-		i++;
+	while (buf[offs] && ' ' == buf[offs])
+		offs++;
 
 	/* 
 	 * Trailing whitespace.  Note that tabs are allowed to be passed
 	 * into the parser as "text", so we only warn about spaces here.
 	 */
 
-	if ('\0' == buf[i] && ' ' == buf[i - 1])
-		man_pmsg(m, ln, i - 1, MANDOCERR_EOLNSPACE);
+	if ('\0' == buf[offs] && ' ' == buf[offs - 1])
+		man_pmsg(m, ln, offs - 1, MANDOCERR_EOLNSPACE);
 
 	/* 
 	 * Remove prior ELINE macro, as it's being clobbered by a new
@@ -542,13 +542,45 @@ man_pmacro(struct man *m, int ln, char *buf, int offs)
 		if (MAN_NSCOPED & man_macros[n->tok].flags)
 			n = n->parent;
 
-		man_vmsg(m, MANDOCERR_LINESCOPE, n->line, n->pos,
-				"%s", man_macronames[n->tok]);
+		mandoc_vmsg(MANDOCERR_LINESCOPE, m->parse, n->line, 
+		    n->pos, "%s breaks %s", man_macronames[tok],
+		    man_macronames[n->tok]);
 
 		man_node_delete(m, n);
 		m->flags &= ~MAN_ELINE;
 	}
 
+	/*
+	 * Remove prior BLINE macro that is being clobbered.
+	 */
+	if ((m->flags & MAN_BLINE) &&
+	    (MAN_BSCOPE & man_macros[tok].flags)) {
+		n = m->last;
+
+		/* Might be a text node like 8 in
+		 * .TP 8
+		 * .SH foo
+		 */
+		if (MAN_TEXT == n->type)
+			n = n->parent;
+
+		/* Remove element that didn't end BLINE, if any. */
+		if ( ! (MAN_BSCOPE & man_macros[n->tok].flags))
+			n = n->parent;
+
+		assert(MAN_HEAD == n->type);
+		n = n->parent;
+		assert(MAN_BLOCK == n->type);
+		assert(MAN_SCOPED & man_macros[n->tok].flags);
+
+		mandoc_vmsg(MANDOCERR_LINESCOPE, m->parse, n->line, 
+		    n->pos, "%s breaks %s", man_macronames[tok],
+		    man_macronames[n->tok]);
+
+		man_node_delete(m, n);
+		m->flags &= ~MAN_BLINE;
+	}
+
 	/*
 	 * Save the fact that we're in the next-line for a block.  In
 	 * this way, embedded roff instructions can "remember" state
@@ -561,10 +593,9 @@ man_pmacro(struct man *m, int ln, char *buf, int offs)
 	/* Call to handler... */
 
 	assert(man_macros[tok].fp);
-	if ( ! (*man_macros[tok].fp)(m, tok, ln, ppos, &i, buf))
+	if ( ! (*man_macros[tok].fp)(m, tok, ln, ppos, &offs, buf))
 		goto err;
 
-out:
 	/* 
 	 * We weren't in a block-line scope when entering the
 	 * above-parsed macro, so return.
@@ -601,7 +632,7 @@ out:
 
 	if ( ! man_unscope(m, m->last->parent, MANDOCERR_MAX))
 		return(0);
-	return(man_body_alloc(m, ln, offs, m->last->tok));
+	return(man_body_alloc(m, ln, ppos, m->last->tok));
 
 err:	/* Error out. */
 
@@ -609,21 +640,6 @@ err:	/* Error out. */
 	return(0);
 }
 
-
-int
-man_vmsg(struct man *man, enum mandocerr t, 
-		int ln, int pos, const char *fmt, ...)
-{
-	char		 buf[256];
-	va_list		 ap;
-
-	va_start(ap, fmt);
-	vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
-	va_end(ap);
-	return((*man->msg)(t, man->data, ln, pos, buf));
-}
-
-
 /*
  * Unlink a node from its context.  If "m" is provided, the last parse
  * point will also be adjusted accordingly.
@@ -664,3 +680,11 @@ man_node_unlink(struct man *m, struct man_node *n)
 	if (m && m->first == n)
 		m->first = NULL;
 }
+
+const struct mparse *
+man_mparse(const struct man *m)
+{
+
+	assert(m && m->parse);
+	return(m->parse);
+}
diff --git a/external/bsd/mdocml/dist/man.cgi.7 b/external/bsd/mdocml/dist/man.cgi.7
new file mode 100644
index 000000000..cab195826
--- /dev/null
+++ b/external/bsd/mdocml/dist/man.cgi.7
@@ -0,0 +1,123 @@
+.Dd December 15, 2011
+.Dt MAN.CGI 7
+.Os
+.Sh NAME
+.Nm man.cgi
+.Nd cgi for manpage query and display
+.Sh SYNOPSIS
+.Nm
+.Sh DESCRIPTION
+The
+.Nm
+script queries and displays manual pages.
+It interfaces with
+.Xr mandocdb 8
+databases cached with
+.Xr catman 8 .
+.Pp
+To use
+.Nm ,
+create a manual cache in
+.Xr catman 8 .
+Assign this directory to the environment variable
+.Ev CACHE_DIR ,
+defaulting to
+.Pa /cache/man.cgi .
+Copy the
+.Pa man.cgi
+script into your CGI directory (see
+.Sx FILES
+for other relevant files).
+.Pp
+Multiple
+.Xr catman 8
+trees may be managed by
+.Nm :
+directories under
+.Ev CACHE_DIR
+containing
+.Pa etc/catman.conf
+are identified as
+.Qq manroots .
+The path of a manroot under
+.Ev CACHE_DIR
+is converted to a name by replacing path separators with spaces.
+.Pp
+Thus, if
+.Ev CACHE_DIR
+is the default
+.Pa /cache/man.cgi ,
+the web-server is jailed to
+.Pa /var/www ,
+and cache subdirectories
+.Pa ./foo/1
+and
+.Pa ./bar/2
+contain
+.Pa etc/catman.conf ,
+.Nm
+will assign these to manroots
+.Qq foo 1
+and
+.Qq bar 2 ,
+respectively.
+These names will appear as choices when searching for manuals.
+.Pp
+If
+.Nm
+finds only one manroot, or none, then the selection box is omitted.
+If no manroot is specified during search, the first manroot is used by
+default.
+.Sh ENVIRONMENT
+.Bl -tag -width Ds
+.It Ev CACHE_DIR
+The absolute path of the
+.Xr catman 8
+cache directory.
+This must not have a trailing slash.
+.It Ev CSS_DIR
+Prepended to CSS file links in outputted HTML files.
+This must not have a trailing slash.
+.El
+.Sh FILES
+.Bl -tag -width Ds
+.It Pa etc/catman.conf
+Built by
+.Xr catman 8
+and must exist at least once under the configuration directory root.
+.It Pa man.css
+Should be visible in the server document root or within
+.Ev CSS_DIR .
+Included in each page after
+.Pa man-cgi.css , 
+ostensibly for
+.Xr mandoc 1
+HTML output styling.
+.It Pa man.cgi.css
+Should be visible in the server document root or within
+.Ev CSS_DIR .
+Included in each page, ostensibly for general
+.Nm
+styling.
+.El
+.Sh COMPATIBILITY
+The
+.Nm
+script is call-compatible with queries from the traditional
+.Pa man.cgi
+script by Wolfram Schneider.
+However, the results may not be quite the same.
+.Sh SEE ALSO
+.Xr catman 8 ,
+.Xr mandocdb 8
+.Sh AUTHORS
+The
+.Nm
+utility was written by
+.An Kristaps Dzonsons ,
+.Mt kristaps@bsd.lv .
+.Sh CAVEATS
+If you're running in a jailed web-server, make sure the
+.Pa /tmp
+directory exists and is writable.
+The databases may need this for scratch space.
diff --git a/external/bsd/mdocml/dist/man.h b/external/bsd/mdocml/dist/man.h
index 2a37d0168..d55504a94 100644
--- a/external/bsd/mdocml/dist/man.h
+++ b/external/bsd/mdocml/dist/man.h
@@ -1,6 +1,6 @@
-/*	$Vendor-Id: man.h,v 1.50 2011/01/01 12:59:17 kristaps Exp $ */
+/*	$Vendor-Id: man.h,v 1.60 2012/01/03 15:16:24 kristaps Exp $ */
 /*
- * Copyright (c) 2009, 2010 Kristaps Dzonsons 
+ * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons 
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -17,9 +17,6 @@
 #ifndef MAN_H
 #define MAN_H
 
-/* 
- * What follows is a list of ALL possible macros. 
- */
 enum	mant {
 	MAN_br = 0,
 	MAN_TH,
@@ -54,12 +51,10 @@ enum	mant {
 	MAN_AT,
 	MAN_in,
 	MAN_ft,
+	MAN_OP,
 	MAN_MAX
 };
 
-/* 
- * Type of a syntax node. 
- */
 enum	man_type {
 	MAN_TEXT,
 	MAN_ELEM,
@@ -67,24 +62,19 @@ enum	man_type {
 	MAN_BLOCK,
 	MAN_HEAD,
 	MAN_BODY,
-	MAN_TBL
+	MAN_TAIL,
+	MAN_TBL,
+	MAN_EQN
 };
 
-/* 
- * Information from prologue. 
- */
 struct	man_meta {
 	char		*msec; /* `TH' section (1, 3p, etc.) */
-	time_t		 date; /* `TH' normalised date */
-	char		*rawdate; /* raw `TH' date */
+	char		*date; /* `TH' normalised date */
 	char		*vol; /* `TH' volume */
 	char		*title; /* `TH' title (e.g., FOO) */
 	char		*source; /* `TH' source (e.g., GNU) */
 };
 
-/* 
- * Single node in tree-linked AST. 
- */
 struct	man_node {
 	struct man_node	*parent; /* parent AST node */
 	struct man_node	*child; /* first child AST node */
@@ -97,33 +87,26 @@ struct	man_node {
 	int		 flags;
 #define	MAN_VALID	(1 << 0) /* has been validated */
 #define	MAN_EOS		(1 << 2) /* at sentence boundary */
+#define	MAN_LINE	(1 << 3) /* first macro/text on line */
 	enum man_type	 type; /* AST node type */
 	char		*string; /* TEXT node argument */
 	struct man_node	*head; /* BLOCK node HEAD ptr */
+	struct man_node *tail; /* BLOCK node TAIL ptr */
 	struct man_node	*body; /* BLOCK node BODY ptr */
 	const struct tbl_span *span; /* TBL */
+	const struct eqn *eqn; /* EQN */
 };
 
-/*
- * Names of macros.  Index is enum mant.  Indexing into this returns
- * the normalised name, e.g., man_macronames[MAN_SH] -> "SH".
- */
+/* Names of macros.  Index is enum mant. */
 extern	const char *const *man_macronames;
 
 __BEGIN_DECLS
 
 struct	man;
 
-void	 	  man_free(struct man *);
-struct	man	 *man_alloc(struct regset *, void *, mandocmsg);
-void		  man_reset(struct man *);
-int	 	  man_parseln(struct man *, int, char *, int);
-int		  man_endparse(struct man *);
-int		  man_addspan(struct man *,
-			const struct tbl_span *);
-
 const struct man_node *man_node(const struct man *);
 const struct man_meta *man_meta(const struct man *);
+const struct mparse   *man_mparse(const struct man *);
 
 __END_DECLS
 
diff --git a/external/bsd/mdocml/dist/man_hash.c b/external/bsd/mdocml/dist/man_hash.c
index 7c31e1b48..bb9d2d4af 100644
--- a/external/bsd/mdocml/dist/man_hash.c
+++ b/external/bsd/mdocml/dist/man_hash.c
@@ -1,4 +1,4 @@
-/*	$Vendor-Id: man_hash.c,v 1.23 2010/07/31 23:52:58 schwarze Exp $ */
+/*	$Vendor-Id: man_hash.c,v 1.25 2011/07/24 18:15:14 kristaps Exp $ */
 /*
  * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons 
  *
@@ -26,13 +26,14 @@
 #include 
 #include 
 
+#include "man.h"
 #include "mandoc.h"
 #include "libman.h"
 
 #define	HASH_DEPTH	 6
 
 #define	HASH_ROW(x) do { \
-		if (isupper((u_char)(x))) \
+		if (isupper((unsigned char)(x))) \
 			(x) -= 65; \
 		else \
 			(x) -= 97; \
@@ -46,7 +47,7 @@
  * macro (the integer value of the enum stored as a char to save a bit
  * of space).
  */
-static	u_char		 table[26 * HASH_DEPTH];
+static	unsigned char	 table[26 * HASH_DEPTH];
 
 /*
  * XXX - this hash has global scope, so if intended for use as a library
@@ -65,13 +66,13 @@ man_hash_init(void)
 	for (i = 0; i < (int)MAN_MAX; i++) {
 		x = man_macronames[i][0];
 
-		assert(isalpha((u_char)x));
+		assert(isalpha((unsigned char)x));
 
 		HASH_ROW(x);
 
 		for (j = 0; j < HASH_DEPTH; j++)
 			if (UCHAR_MAX == table[x + j]) {
-				table[x + j] = (u_char)i;
+				table[x + j] = (unsigned char)i;
 				break;
 			}
 
@@ -88,7 +89,7 @@ man_hash_find(const char *tmp)
 
 	if ('\0' == (x = tmp[0]))
 		return(MAN_MAX);
-	if ( ! (isalpha((u_char)x)))
+	if ( ! (isalpha((unsigned char)x)))
 		return(MAN_MAX);
 
 	HASH_ROW(x);
diff --git a/external/bsd/mdocml/dist/man_html.c b/external/bsd/mdocml/dist/man_html.c
index 53fc62cc5..51bb5bbd7 100644
--- a/external/bsd/mdocml/dist/man_html.c
+++ b/external/bsd/mdocml/dist/man_html.c
@@ -1,6 +1,6 @@
-/*	$Vendor-Id: man_html.c,v 1.62 2011/01/07 13:20:58 kristaps Exp $ */
+/*	$Vendor-Id: man_html.c,v 1.86 2012/01/03 15:16:24 kristaps Exp $ */
 /*
- * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons 
+ * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons 
  *
  * 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 @@
 /* FIXME: have PD set the default vspace width. */
 
 #define	INDENT		  5
-#define	HALFINDENT	  3
 
 #define	MAN_ARGS	  const struct man_meta *m, \
 			  const struct man_node *n, \
@@ -53,30 +52,31 @@ struct	htmlman {
 	int		(*post)(MAN_ARGS);
 };
 
+static	void		  print_bvspace(struct html *, 
+				const struct man_node *);
 static	void		  print_man(MAN_ARGS);
 static	void		  print_man_head(MAN_ARGS);
 static	void		  print_man_nodelist(MAN_ARGS);
 static	void		  print_man_node(MAN_ARGS);
-
 static	int		  a2width(const struct man_node *,
 				struct roffsu *);
-
+static	int		  man_B_pre(MAN_ARGS);
+static	int		  man_HP_pre(MAN_ARGS);
+static	int		  man_IP_pre(MAN_ARGS);
+static	int		  man_I_pre(MAN_ARGS);
+static	int		  man_OP_pre(MAN_ARGS);
+static	int		  man_PP_pre(MAN_ARGS);
+static	int		  man_RS_pre(MAN_ARGS);
+static	int		  man_SH_pre(MAN_ARGS);
+static	int		  man_SM_pre(MAN_ARGS);
+static	int		  man_SS_pre(MAN_ARGS);
 static	int		  man_alt_pre(MAN_ARGS);
 static	int		  man_br_pre(MAN_ARGS);
 static	int		  man_ign_pre(MAN_ARGS);
 static	int		  man_in_pre(MAN_ARGS);
 static	int		  man_literal_pre(MAN_ARGS);
 static	void		  man_root_post(MAN_ARGS);
-static	int		  man_root_pre(MAN_ARGS);
-static	int		  man_B_pre(MAN_ARGS);
-static	int		  man_HP_pre(MAN_ARGS);
-static	int		  man_I_pre(MAN_ARGS);
-static	int		  man_IP_pre(MAN_ARGS);
-static	int		  man_PP_pre(MAN_ARGS);
-static	int		  man_RS_pre(MAN_ARGS);
-static	int		  man_SH_pre(MAN_ARGS);
-static	int		  man_SM_pre(MAN_ARGS);
-static	int		  man_SS_pre(MAN_ARGS);
+static	void		  man_root_pre(MAN_ARGS);
 
 static	const struct htmlman mans[MAN_MAX] = {
 	{ man_br_pre, NULL }, /* br */
@@ -100,7 +100,7 @@ static	const struct htmlman mans[MAN_MAX] = {
 	{ man_I_pre, NULL }, /* I */
 	{ man_alt_pre, NULL }, /* IR */
 	{ man_alt_pre, NULL }, /* RI */
-	{ NULL, NULL }, /* na */
+	{ man_ign_pre, NULL }, /* na */
 	{ man_br_pre, NULL }, /* sp */
 	{ man_literal_pre, NULL }, /* nf */
 	{ man_literal_pre, NULL }, /* fi */
@@ -112,40 +112,61 @@ static	const struct htmlman mans[MAN_MAX] = {
 	{ man_ign_pre, NULL }, /* AT */
 	{ man_in_pre, NULL }, /* in */
 	{ man_ign_pre, NULL }, /* ft */
+	{ man_OP_pre, NULL }, /* OP */
 };
 
+/*
+ * Printing leading vertical space before a block.
+ * This is used for the paragraph macros.
+ * The rules are pretty simple, since there's very little nesting going
+ * on here.  Basically, if we're the first within another block (SS/SH),
+ * then don't emit vertical space.  If we are (RS), then do.  If not the
+ * first, print it.
+ */
+static void
+print_bvspace(struct html *h, const struct man_node *n)
+{
+
+	if (n->body && n->body->child)
+		if (MAN_TBL == n->body->child->type)
+			return;
+
+	if (MAN_ROOT == n->parent->type || MAN_RS != n->parent->tok)
+		if (NULL == n->prev)
+			return;
+
+	print_otag(h, TAG_P, 0, NULL);
+}
 
 void
 html_man(void *arg, const struct man *m)
 {
-	struct html	*h;
-	struct tag	*t;
 	struct mhtml	 mh;
 
-	h = (struct html *)arg;
-
-	print_gen_decls(h);
-
 	memset(&mh, 0, sizeof(struct mhtml));
-
-	t = print_otag(h, TAG_HTML, 0, NULL);
-	print_man(man_meta(m), man_node(m), &mh, h);
-	print_tagq(h, t);
-
-	printf("\n");
+	print_man(man_meta(m), man_node(m), &mh, (struct html *)arg);
+	putchar('\n');
 }
 
-
 static void
 print_man(MAN_ARGS) 
 {
-	struct tag	*t;
+	struct tag	*t, *tt;
+	struct htmlpair	 tag;
 
-	t = print_otag(h, TAG_HEAD, 0, NULL);
-	print_man_head(m, n, mh, h);
-	print_tagq(h, t);
+	PAIR_CLASS_INIT(&tag, "mandoc");
+
+	if ( ! (HTML_FRAGMENT & h->oflags)) {
+		print_gen_decls(h);
+		t = print_otag(h, TAG_HTML, 0, NULL);
+		tt = print_otag(h, TAG_HEAD, 0, NULL);
+		print_man_head(m, n, mh, h);
+		print_tagq(h, tt);
+		print_otag(h, TAG_BODY, 0, NULL);
+		print_otag(h, TAG_DIV, 1, &tag);
+	} else 
+		t = print_otag(h, TAG_DIV, 1, &tag);
 
-	t = print_otag(h, TAG_BODY, 0, NULL);
 	print_man_nodelist(m, n, mh, h);
 	print_tagq(h, t);
 }
@@ -157,9 +178,9 @@ print_man_head(MAN_ARGS)
 {
 
 	print_gen_head(h);
-	bufinit(h);
-	buffmt(h, "%s(%s)", m->title, m->msec);
-
+	assert(m->title);
+	assert(m->msec);
+	bufcat_fmt(h, "%s(%s)", m->title, m->msec);
 	print_otag(h, TAG_TITLE, 0, NULL);
 	print_text(h, h->buf);
 }
@@ -184,36 +205,58 @@ print_man_node(MAN_ARGS)
 	child = 1;
 	t = h->tags.head;
 
-	bufinit(h);
-
-	/*
-	 * FIXME: embedded elements within next-line scopes (e.g., `br'
-	 * within an empty `B') will cause formatting to be forgotten
-	 * due to scope closing out.
-	 */
-
 	switch (n->type) {
 	case (MAN_ROOT):
-		child = man_root_pre(m, n, mh, h);
+		man_root_pre(m, n, mh, h);
 		break;
 	case (MAN_TEXT):
-		print_text(h, n->string);
-		if (MANH_LITERAL & mh->fl)
+		/*
+		 * If we have a blank line, output a vertical space.
+		 * If we have a space as the first character, break
+		 * before printing the line's data.
+		 */
+		if ('\0' == *n->string) {
+			print_otag(h, TAG_P, 0, NULL);
+			return;
+		}
+
+		if (' ' == *n->string && MAN_LINE & n->flags)
 			print_otag(h, TAG_BR, 0, NULL);
+		else if (MANH_LITERAL & mh->fl && n->prev)
+			print_otag(h, TAG_BR, 0, NULL);
+
+		print_text(h, n->string);
 		return;
-	case (MAN_TBL):
-		print_tbl(h, n->span);
+	case (MAN_EQN):
+		print_eqn(h, n->eqn);
 		break;
+	case (MAN_TBL):
+		/*
+		 * This will take care of initialising all of the table
+		 * state data for the first table, then tearing it down
+		 * for the last one.
+		 */
+		print_tbl(h, n->span);
+		return;
 	default:
 		/* 
 		 * Close out scope of font prior to opening a macro
-		 * scope.  Assert that the metafont is on the top of the
-		 * stack (it's never nested).
+		 * scope.
 		 */
 		if (HTMLFONT_NONE != h->metac) {
 			h->metal = h->metac;
 			h->metac = HTMLFONT_NONE;
 		}
+
+		/*
+		 * Close out the current table, if it's open, and unset
+		 * the "meta" table state.  This will be reopened on the
+		 * next table element.
+		 */
+		if (h->tblt) {
+			print_tblclose(h);
+			t = h->tags.head;
+		}
 		if (mans[n->tok].pre)
 			child = (*mans[n->tok].pre)(m, n, mh, h);
 		break;
@@ -225,13 +268,11 @@ print_man_node(MAN_ARGS)
 	/* This will automatically close out any font scope. */
 	print_stagq(h, t);
 
-	bufinit(h);
-
 	switch (n->type) {
 	case (MAN_ROOT):
 		man_root_post(m, n, mh, h);
 		break;
-	case (MAN_TBL):
+	case (MAN_EQN):
 		break;
 	default:
 		if (mans[n->tok].post)
@@ -255,7 +296,7 @@ a2width(const struct man_node *n, struct roffsu *su)
 
 
 /* ARGSUSED */
-static int
+static void
 man_root_pre(MAN_ARGS)
 {
 	struct htmlpair	 tag[3];
@@ -266,19 +307,18 @@ man_root_pre(MAN_ARGS)
 	if (m->vol)
 		(void)strlcat(b, m->vol, BUFSIZ);
 
+	assert(m->title);
+	assert(m->msec);
 	snprintf(title, BUFSIZ - 1, "%s(%s)", m->title, m->msec);
 
 	PAIR_SUMMARY_INIT(&tag[0], "Document Header");
 	PAIR_CLASS_INIT(&tag[1], "head");
-	if (NULL == h->style) {
-		PAIR_INIT(&tag[2], ATTR_WIDTH, "100%");
-		t = print_otag(h, TAG_TABLE, 3, tag);
-		PAIR_INIT(&tag[0], ATTR_WIDTH, "30%");
-		print_otag(h, TAG_COL, 1, tag);
-		print_otag(h, TAG_COL, 1, tag);
-		print_otag(h, TAG_COL, 1, tag);
-	} else
-		t = print_otag(h, TAG_TABLE, 2, tag);
+	PAIR_INIT(&tag[2], ATTR_WIDTH, "100%");
+	t = print_otag(h, TAG_TABLE, 3, tag);
+	PAIR_INIT(&tag[0], ATTR_WIDTH, "30%");
+	print_otag(h, TAG_COL, 1, tag);
+	print_otag(h, TAG_COL, 1, tag);
+	print_otag(h, TAG_COL, 1, tag);
 
 	print_otag(h, TAG_TBODY, 0, NULL);
 
@@ -286,30 +326,20 @@ man_root_pre(MAN_ARGS)
 
 	PAIR_CLASS_INIT(&tag[0], "head-ltitle");
 	print_otag(h, TAG_TD, 1, tag);
-
 	print_text(h, title);
 	print_stagq(h, tt);
 
 	PAIR_CLASS_INIT(&tag[0], "head-vol");
-	if (NULL == h->style) {
-		PAIR_INIT(&tag[1], ATTR_ALIGN, "center");
-		print_otag(h, TAG_TD, 2, tag);
-	} else 
-		print_otag(h, TAG_TD, 1, tag);
-
+	PAIR_INIT(&tag[1], ATTR_ALIGN, "center");
+	print_otag(h, TAG_TD, 2, tag);
 	print_text(h, b);
 	print_stagq(h, tt);
 
 	PAIR_CLASS_INIT(&tag[0], "head-rtitle");
-	if (NULL == h->style) {
-		PAIR_INIT(&tag[1], ATTR_ALIGN, "right");
-		print_otag(h, TAG_TD, 2, tag);
-	} else 
-		print_otag(h, TAG_TD, 1, tag);
-
+	PAIR_INIT(&tag[1], ATTR_ALIGN, "right");
+	print_otag(h, TAG_TD, 2, tag);
 	print_text(h, title);
 	print_tagq(h, t);
-	return(1);
 }
 
 
@@ -319,38 +349,27 @@ man_root_post(MAN_ARGS)
 {
 	struct htmlpair	 tag[3];
 	struct tag	*t, *tt;
-	char		 b[DATESIZ];
-
-	if (m->rawdate)
-		strlcpy(b, m->rawdate, DATESIZ);
-	else
-		time2a(m->date, b, DATESIZ);
 
 	PAIR_SUMMARY_INIT(&tag[0], "Document Footer");
 	PAIR_CLASS_INIT(&tag[1], "foot");
-	if (NULL == h->style) {
-		PAIR_INIT(&tag[2], ATTR_WIDTH, "100%");
-		t = print_otag(h, TAG_TABLE, 3, tag);
-		PAIR_INIT(&tag[0], ATTR_WIDTH, "50%");
-		print_otag(h, TAG_COL, 1, tag);
-		print_otag(h, TAG_COL, 1, tag);
-	} else
-		t = print_otag(h, TAG_TABLE, 2, tag);
+	PAIR_INIT(&tag[2], ATTR_WIDTH, "100%");
+	t = print_otag(h, TAG_TABLE, 3, tag);
+	PAIR_INIT(&tag[0], ATTR_WIDTH, "50%");
+	print_otag(h, TAG_COL, 1, tag);
+	print_otag(h, TAG_COL, 1, tag);
 
 	tt = print_otag(h, TAG_TR, 0, NULL);
 
 	PAIR_CLASS_INIT(&tag[0], "foot-date");
 	print_otag(h, TAG_TD, 1, tag);
 
-	print_text(h, b);
+	assert(m->date);
+	print_text(h, m->date);
 	print_stagq(h, tt);
 
 	PAIR_CLASS_INIT(&tag[0], "foot-os");
-	if (NULL == h->style) {
-		PAIR_INIT(&tag[1], ATTR_ALIGN, "right");
-		print_otag(h, TAG_TD, 2, tag);
-	} else 
-		print_otag(h, TAG_TD, 1, tag);
+	PAIR_INIT(&tag[1], ATTR_ALIGN, "right");
+	print_otag(h, TAG_TD, 2, tag);
 
 	if (m->source)
 		print_text(h, m->source);
@@ -358,7 +377,6 @@ man_root_post(MAN_ARGS)
 }
 
 
-
 /* ARGSUSED */
 static int
 man_br_pre(MAN_ARGS)
@@ -369,11 +387,13 @@ man_br_pre(MAN_ARGS)
 	SCALE_VS_INIT(&su, 1);
 
 	if (MAN_sp == n->tok) {
-		if (n->child)
-			a2roffsu(n->child->string, &su, SCALE_VS);
+		if (NULL != (n = n->child))
+			if ( ! a2roffsu(n->string, &su, SCALE_VS))
+				SCALE_VS_INIT(&su, atoi(n->string));
 	} else
 		su.scale = 0;
 
+	bufinit(h);
 	bufcat_su(h, "height", &su);
 	PAIR_STYLE_INIT(&tag, h);
 	print_otag(h, TAG_DIV, 1, &tag);
@@ -384,7 +404,6 @@ man_br_pre(MAN_ARGS)
 	return(0);
 }
 
-
 /* ARGSUSED */
 static int
 man_SH_pre(MAN_ARGS)
@@ -392,6 +411,7 @@ man_SH_pre(MAN_ARGS)
 	struct htmlpair	 tag;
 
 	if (MAN_BLOCK == n->type) {
+		mh->fl &= ~MANH_LITERAL;
 		PAIR_CLASS_INIT(&tag, "section");
 		print_otag(h, TAG_DIV, 1, &tag);
 		return(1);
@@ -402,16 +422,20 @@ man_SH_pre(MAN_ARGS)
 	return(1);
 }
 
-
 /* ARGSUSED */
 static int
 man_alt_pre(MAN_ARGS)
 {
 	const struct man_node	*nn;
-	int		 i;
+	int		 i, savelit;
 	enum htmltag	 fp;
 	struct tag	*t;
 
+	if ((savelit = mh->fl & MANH_LITERAL)) 
+		print_otag(h, TAG_BR, 0, NULL);
+
+	mh->fl &= ~MANH_LITERAL;
+
 	for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
 		t = NULL;
 		switch (n->tok) {
@@ -450,10 +474,12 @@ man_alt_pre(MAN_ARGS)
 			print_tagq(h, t);
 	}
 
+	if (savelit)
+		mh->fl |= MANH_LITERAL;
+
 	return(0);
 }
 
-
 /* ARGSUSED */
 static int
 man_SM_pre(MAN_ARGS)
@@ -465,7 +491,6 @@ man_SM_pre(MAN_ARGS)
 	return(1);
 }
 
-
 /* ARGSUSED */
 static int
 man_SS_pre(MAN_ARGS)
@@ -473,6 +498,7 @@ man_SS_pre(MAN_ARGS)
 	struct htmlpair	 tag;
 
 	if (MAN_BLOCK == n->type) {
+		mh->fl &= ~MANH_LITERAL;
 		PAIR_CLASS_INIT(&tag, "subsection");
 		print_otag(h, TAG_DIV, 1, &tag);
 		return(1);
@@ -483,7 +509,6 @@ man_SS_pre(MAN_ARGS)
 	return(1);
 }
 
-
 /* ARGSUSED */
 static int
 man_PP_pre(MAN_ARGS)
@@ -491,67 +516,29 @@ man_PP_pre(MAN_ARGS)
 
 	if (MAN_HEAD == n->type)
 		return(0);
-	else if (MAN_BODY == n->type && n->prev)
-		print_otag(h, TAG_P, 0, NULL);
+	else if (MAN_BLOCK == n->type)
+		print_bvspace(h, n);
 
 	return(1);
 }
 
-
 /* ARGSUSED */
 static int
 man_IP_pre(MAN_ARGS)
 {
-	struct roffsu		 su;
-	struct htmlpair	 	 tag;
 	const struct man_node	*nn;
 
-	/*
-	 * This scattering of 1-BU margins and pads is to make sure that
-	 * when text overruns its box, the subsequent text isn't flush
-	 * up against it.  However, the rest of the right-hand box must
-	 * also be adjusted in consideration of this 1-BU space.
-	 */
-
 	if (MAN_BODY == n->type) { 
-		print_otag(h, TAG_TD, 0, NULL);
+		print_otag(h, TAG_DD, 0, NULL);
+		return(1);
+	} else if (MAN_HEAD != n->type) {
+		print_otag(h, TAG_DL, 0, NULL);
 		return(1);
 	}
 
-	nn = MAN_BLOCK == n->type ? 
-		n->head->child : n->parent->head->child;
+	/* FIXME: width specification. */
 
-	SCALE_HS_INIT(&su, INDENT);
-
-	/* Width is the second token. */
-
-	if (MAN_IP == n->tok && NULL != nn)
-		if (NULL != (nn = nn->next))
-			a2width(nn, &su);
-
-	/* Width is the first token. */
-
-	if (MAN_TP == n->tok && NULL != nn) {
-		/* Skip past non-text children. */
-		while (nn && MAN_TEXT != nn->type)
-			nn = nn->next;
-		if (nn)
-			a2width(nn, &su);
-	}
-
-	if (MAN_BLOCK == n->type) {
-		print_otag(h, TAG_P, 0, NULL);
-		print_otag(h, TAG_TABLE, 0, NULL);
-		bufcat_su(h, "width", &su);
-		PAIR_STYLE_INIT(&tag, h);
-		print_otag(h, TAG_COL, 1, &tag);
-		print_otag(h, TAG_COL, 0, NULL);
-		print_otag(h, TAG_TBODY, 0, NULL);
-		print_otag(h, TAG_TR, 0, NULL);
-		return(1);
-	} 
-
-	print_otag(h, TAG_TD, 0, NULL);
+	print_otag(h, TAG_DT, 0, NULL);
 
 	/* For IP, only print the first header element. */
 
@@ -568,7 +555,6 @@ man_IP_pre(MAN_ARGS)
 	return(0);
 }
 
-
 /* ARGSUSED */
 static int
 man_HP_pre(MAN_ARGS)
@@ -577,35 +563,57 @@ man_HP_pre(MAN_ARGS)
 	struct roffsu	 su;
 	const struct man_node *np;
 
-	np = MAN_BLOCK == n->type ? 
-		n->head->child : 
-		n->parent->head->child;
+	if (MAN_HEAD == n->type)
+		return(0);
+	else if (MAN_BLOCK != n->type)
+		return(1);
+
+	np = n->head->child;
 
 	if (NULL == np || ! a2width(np, &su))
 		SCALE_HS_INIT(&su, INDENT);
 
-	if (MAN_HEAD == n->type) {
-		print_otag(h, TAG_TD, 0, NULL);
-		return(0);
-	} else if (MAN_BLOCK == n->type) {
-		print_otag(h, TAG_P, 0, NULL);
-		print_otag(h, TAG_TABLE, 0, NULL);
-		bufcat_su(h, "width", &su);
-		PAIR_STYLE_INIT(&tag, h);
-		print_otag(h, TAG_COL, 1, &tag);
-		print_otag(h, TAG_COL, 0, NULL);
-		print_otag(h, TAG_TBODY, 0, NULL);
-		print_otag(h, TAG_TR, 0, NULL);
-		return(1);
-	}
+	bufinit(h);
 
+	print_bvspace(h, n);
+	bufcat_su(h, "margin-left", &su);
 	su.scale = -su.scale;
 	bufcat_su(h, "text-indent", &su);
 	PAIR_STYLE_INIT(&tag, h);
-	print_otag(h, TAG_TD, 1, &tag);
+	print_otag(h, TAG_P, 1, &tag);
 	return(1);
 }
 
+/* ARGSUSED */
+static int
+man_OP_pre(MAN_ARGS)
+{
+	struct tag	*tt;
+	struct htmlpair	 tag;
+
+	print_text(h, "[");
+	h->flags |= HTML_NOSPACE;
+	PAIR_CLASS_INIT(&tag, "opt");
+	tt = print_otag(h, TAG_SPAN, 1, &tag);
+
+	if (NULL != (n = n->child)) {
+		print_otag(h, TAG_B, 0, NULL);
+		print_text(h, n->string);
+	}
+
+	print_stagq(h, tt);
+
+	if (NULL != n && NULL != n->next) {
+		print_otag(h, TAG_I, 0, NULL);
+		print_text(h, n->next->string);
+	}
+
+	print_stagq(h, tt);
+	h->flags |= HTML_NOSPACE;
+	print_text(h, "]");
+	return(0);
+}
+
 
 /* ARGSUSED */
 static int
@@ -616,7 +624,6 @@ man_B_pre(MAN_ARGS)
 	return(1);
 }
 
-
 /* ARGSUSED */
 static int
 man_I_pre(MAN_ARGS)
@@ -626,22 +633,20 @@ man_I_pre(MAN_ARGS)
 	return(1);
 }
 
-
 /* ARGSUSED */
 static int
 man_literal_pre(MAN_ARGS)
 {
 
-	if (MAN_nf == n->tok) {
+	if (MAN_nf != n->tok) {
 		print_otag(h, TAG_BR, 0, NULL);
-		mh->fl |= MANH_LITERAL;
-	} else
 		mh->fl &= ~MANH_LITERAL;
+	} else
+		mh->fl |= MANH_LITERAL;
 
-	return(1);
+	return(0);
 }
 
-
 /* ARGSUSED */
 static int
 man_in_pre(MAN_ARGS)
@@ -651,7 +656,6 @@ man_in_pre(MAN_ARGS)
 	return(0);
 }
 
-
 /* ARGSUSED */
 static int
 man_ign_pre(MAN_ARGS)
@@ -660,7 +664,6 @@ man_ign_pre(MAN_ARGS)
 	return(0);
 }
 
-
 /* ARGSUSED */
 static int
 man_RS_pre(MAN_ARGS)
@@ -677,6 +680,7 @@ man_RS_pre(MAN_ARGS)
 	if (n->head->child)
 		a2width(n->head->child, &su);
 
+	bufinit(h);
 	bufcat_su(h, "margin-left", &su);
 	PAIR_STYLE_INIT(&tag, h);
 	print_otag(h, TAG_DIV, 1, &tag);
diff --git a/external/bsd/mdocml/dist/man_macro.c b/external/bsd/mdocml/dist/man_macro.c
index fc9a80ba4..aacb202af 100644
--- a/external/bsd/mdocml/dist/man_macro.c
+++ b/external/bsd/mdocml/dist/man_macro.c
@@ -1,6 +1,6 @@
-/*	$Vendor-Id: man_macro.c,v 1.54 2010/12/08 10:58:22 kristaps Exp $ */
+/*	$Vendor-Id: man_macro.c,v 1.71 2012/01/03 15:16:24 kristaps Exp $ */
 /*
- * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons 
+ * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons 
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -23,7 +23,9 @@
 #include 
 #include 
 
+#include "man.h"
 #include "mandoc.h"
+#include "libmandoc.h"
 #include "libman.h"
 
 enum	rew {
@@ -36,6 +38,8 @@ static	int		 blk_close(MACRO_PROT_ARGS);
 static	int		 blk_exp(MACRO_PROT_ARGS);
 static	int		 blk_imp(MACRO_PROT_ARGS);
 static	int		 in_line_eoln(MACRO_PROT_ARGS);
+static	int		 man_args(struct man *, int, 
+				int *, char *, char **);
 
 static	int		 rew_scope(enum man_type, 
 				struct man *, enum mant);
@@ -43,20 +47,20 @@ static	enum rew	 rew_dohalt(enum mant, enum man_type,
 				const struct man_node *);
 static	enum rew	 rew_block(enum mant, enum man_type, 
 				const struct man_node *);
-static	int		 rew_warn(struct man *, 
+static	void		 rew_warn(struct man *, 
 				struct man_node *, enum mandocerr);
 
 const	struct man_macro __man_macros[MAN_MAX] = {
 	{ in_line_eoln, MAN_NSCOPED }, /* br */
-	{ in_line_eoln, 0 }, /* TH */
-	{ blk_imp, MAN_SCOPED }, /* SH */
-	{ blk_imp, MAN_SCOPED }, /* SS */
-	{ blk_imp, MAN_SCOPED | MAN_FSCOPED }, /* TP */
-	{ blk_imp, 0 }, /* LP */
-	{ blk_imp, 0 }, /* PP */
-	{ blk_imp, 0 }, /* P */
-	{ blk_imp, 0 }, /* IP */
-	{ blk_imp, 0 }, /* HP */
+	{ in_line_eoln, MAN_BSCOPE }, /* TH */
+	{ blk_imp, MAN_BSCOPE | MAN_SCOPED }, /* SH */
+	{ blk_imp, MAN_BSCOPE | MAN_SCOPED }, /* SS */
+	{ blk_imp, MAN_BSCOPE | MAN_SCOPED | MAN_FSCOPED }, /* TP */
+	{ blk_imp, MAN_BSCOPE }, /* LP */
+	{ blk_imp, MAN_BSCOPE }, /* PP */
+	{ blk_imp, MAN_BSCOPE }, /* P */
+	{ blk_imp, MAN_BSCOPE }, /* IP */
+	{ blk_imp, MAN_BSCOPE }, /* HP */
 	{ in_line_eoln, MAN_SCOPED }, /* SM */
 	{ in_line_eoln, MAN_SCOPED }, /* SB */
 	{ in_line_eoln, 0 }, /* BI */
@@ -70,8 +74,8 @@ const	struct man_macro __man_macros[MAN_MAX] = {
 	{ in_line_eoln, 0 }, /* RI */
 	{ in_line_eoln, MAN_NSCOPED }, /* na */
 	{ in_line_eoln, MAN_NSCOPED }, /* sp */
-	{ in_line_eoln, 0 }, /* nf */
-	{ in_line_eoln, 0 }, /* fi */
+	{ in_line_eoln, MAN_BSCOPE }, /* nf */
+	{ in_line_eoln, MAN_BSCOPE }, /* fi */
 	{ blk_close, 0 }, /* RE */
 	{ blk_exp, MAN_EXPLICIT }, /* RS */
 	{ in_line_eoln, 0 }, /* DT */
@@ -80,6 +84,7 @@ const	struct man_macro __man_macros[MAN_MAX] = {
 	{ in_line_eoln, 0 }, /* AT */
 	{ in_line_eoln, 0 }, /* in */
 	{ in_line_eoln, 0 }, /* ft */
+	{ in_line_eoln, 0 }, /* OP */
 };
 
 const	struct man_macro * const man_macros = __man_macros;
@@ -88,17 +93,19 @@ const	struct man_macro * const man_macros = __man_macros;
 /*
  * Warn when "n" is an explicit non-roff macro.
  */
-static int
+static void
 rew_warn(struct man *m, struct man_node *n, enum mandocerr er)
 {
 
 	if (er == MANDOCERR_MAX || MAN_BLOCK != n->type)
-		return(1);
+		return;
 	if (MAN_VALID & n->flags)
-		return(1);
+		return;
 	if ( ! (MAN_EXPLICIT & man_macros[n->tok].flags))
-		return(1);
-	return(man_nmsg(m, n, er));
+		return;
+
+	assert(er < MANDOCERR_FATAL);
+	man_nmsg(m, n, er);
 }
 
 
@@ -107,30 +114,35 @@ rew_warn(struct man *m, struct man_node *n, enum mandocerr er)
  * will be used if an explicit block scope is being closed out.
  */
 int
-man_unscope(struct man *m, const struct man_node *n, 
+man_unscope(struct man *m, const struct man_node *to, 
 		enum mandocerr er)
 {
+	struct man_node	*n;
 
-	assert(n);
+	assert(to);
+
+	m->next = MAN_NEXT_SIBLING;
 
 	/* LINTED */
-	while (m->last != n) {
-		if ( ! rew_warn(m, m->last, er))
-			return(0);
+	while (m->last != to) {
+		/*
+		 * Save the parent here, because we may delete the
+		 * m->last node in the post-validation phase and reset
+		 * it to m->last->parent, causing a step in the closing
+		 * out to be lost.
+		 */
+		n = m->last->parent;
+		rew_warn(m, m->last, er);
 		if ( ! man_valid_post(m))
 			return(0);
-		m->last = m->last->parent;
+		m->last = n;
 		assert(m->last);
 	}
 
-	if ( ! rew_warn(m, m->last, er))
-		return(0);
+	rew_warn(m, m->last, er);
 	if ( ! man_valid_post(m))
 		return(0);
 
-	m->next = MAN_ROOT == m->last->type ? 
-		MAN_NEXT_CHILD : MAN_NEXT_SIBLING;
-
 	return(1);
 }
 
@@ -271,8 +283,7 @@ blk_close(MACRO_PROT_ARGS)
 			break;
 
 	if (NULL == nn)
-		if ( ! man_pmsg(m, line, ppos, MANDOCERR_NOSCOPE))
-			return(0);
+		man_pmsg(m, line, ppos, MANDOCERR_NOSCOPE);
 
 	if ( ! rew_scope(MAN_BODY, m, ntok))
 		return(0);
@@ -287,7 +298,7 @@ blk_close(MACRO_PROT_ARGS)
 int
 blk_exp(MACRO_PROT_ARGS)
 {
-	int		 w, la;
+	int		 la;
 	char		*p;
 
 	/* 
@@ -296,11 +307,6 @@ blk_exp(MACRO_PROT_ARGS)
 	 * anywhere.
 	 */
 
-	if ( ! rew_scope(MAN_BODY, m, tok))
-		return(0);
-	if ( ! rew_scope(MAN_BLOCK, m, tok))
-		return(0);
-
 	if ( ! man_block_alloc(m, line, ppos, tok))
 		return(0);
 	if ( ! man_head_alloc(m, line, ppos, tok))
@@ -308,13 +314,8 @@ blk_exp(MACRO_PROT_ARGS)
 
 	for (;;) {
 		la = *pos;
-		w = man_args(m, line, pos, buf, &p);
-
-		if (-1 == w)
-			return(0);
-		if (0 == w)
+		if ( ! man_args(m, line, pos, buf, &p))
 			break;
-
 		if ( ! man_word_alloc(m, line, la, p))
 			return(0);
 	}
@@ -339,7 +340,7 @@ blk_exp(MACRO_PROT_ARGS)
 int
 blk_imp(MACRO_PROT_ARGS)
 {
-	int		 w, la;
+	int		 la;
 	char		*p;
 	struct man_node	*n;
 
@@ -363,13 +364,8 @@ blk_imp(MACRO_PROT_ARGS)
 
 	for (;;) {
 		la = *pos;
-		w = man_args(m, line, pos, buf, &p);
-
-		if (-1 == w)
-			return(0);
-		if (0 == w)
+		if ( ! man_args(m, line, pos, buf, &p))
 			break;
-
 		if ( ! man_word_alloc(m, line, la, p))
 			return(0);
 	}
@@ -397,7 +393,7 @@ blk_imp(MACRO_PROT_ARGS)
 int
 in_line_eoln(MACRO_PROT_ARGS)
 {
-	int		 w, la;
+	int		 la;
 	char		*p;
 	struct man_node	*n;
 
@@ -408,11 +404,7 @@ in_line_eoln(MACRO_PROT_ARGS)
 
 	for (;;) {
 		la = *pos;
-		w = man_args(m, line, pos, buf, &p);
-
-		if (-1 == w)
-			return(0);
-		if (0 == w)
+		if ( ! man_args(m, line, pos, buf, &p))
 			break;
 		if ( ! man_word_alloc(m, line, la, p))
 			return(0);
@@ -436,6 +428,9 @@ in_line_eoln(MACRO_PROT_ARGS)
 		assert( ! (MAN_SCOPED & man_macros[tok].flags));
 		m->flags |= MAN_ILINE;
 	}
+
+	assert(MAN_ROOT != m->last->type);
+	m->next = MAN_NEXT_SIBLING;
 	
 	/*
 	 * Rewind our element scope.  Note that when TH is pruned, we'll
@@ -461,9 +456,6 @@ in_line_eoln(MACRO_PROT_ARGS)
 	if (m->last->type != MAN_ROOT && ! man_valid_post(m))
 		return(0);
 
-	m->next = MAN_ROOT == m->last->type ?
-		MAN_NEXT_CHILD : MAN_NEXT_SIBLING;
-
 	return(1);
 }
 
@@ -475,3 +467,18 @@ man_macroend(struct man *m)
 	return(man_unscope(m, m->first, MANDOCERR_SCOPEEXIT));
 }
 
+static int
+man_args(struct man *m, int line, int *pos, char *buf, char **v)
+{
+	char	 *start;
+
+	assert(*pos);
+	*v = start = buf + *pos;
+	assert(' ' != *start);
+
+	if ('\0' == *start)
+		return(0);
+
+	*v = mandoc_getarg(m->parse, v, line, pos);
+	return(1);
+}
diff --git a/external/bsd/mdocml/dist/man_term.c b/external/bsd/mdocml/dist/man_term.c
index dd479885c..d5bdb7487 100644
--- a/external/bsd/mdocml/dist/man_term.c
+++ b/external/bsd/mdocml/dist/man_term.c
@@ -1,6 +1,6 @@
-/*	$Vendor-Id: man_term.c,v 1.94 2011/01/04 01:23:18 schwarze Exp $ */
+/*	$Vendor-Id: man_term.c,v 1.127 2012/01/03 15:16:24 kristaps Exp $ */
 /*
- * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons 
+ * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons 
  * Copyright (c) 2010, 2011 Ingo Schwarze 
  *
  * Permission to use, copy, modify, and distribute this software for any
@@ -31,32 +31,19 @@
 #include "out.h"
 #include "man.h"
 #include "term.h"
-#include "chars.h"
 #include "main.h"
 
-#define	INDENT		  7
-#define	HALFINDENT	  3
+#define	MAXMARGINS	  64 /* maximum number of indented scopes */
 
 /* FIXME: have PD set the default vspace width. */
 
 struct	mtermp {
 	int		  fl;
 #define	MANT_LITERAL	 (1 << 0)
-	/* 
-	 * Default amount to indent the left margin after leading text
-	 * has been printed (e.g., `HP' left-indent, `TP' and `IP' body
-	 * indent).  This needs to be saved because `HP' and so on, if
-	 * not having a specified value, must default.
-	 *
-	 * Note that this is the indentation AFTER the left offset, so
-	 * the total offset is usually offset + lmargin.
-	 */
-	size_t		  lmargin;
-	/*
-	 * The default offset, i.e., the amount between any text and the
-	 * page boundary.
-	 */
-	size_t		  offset;
+	size_t		  lmargin[MAXMARGINS]; /* margins (incl. visible page) */
+	int		  lmargincur; /* index of current margin */
+	int		  lmarginsz; /* actual number of nested margins */
+	size_t		  offset; /* default offset to visible page */
 };
 
 #define	DECL_ARGS 	  struct termp *p, \
@@ -81,21 +68,22 @@ static	void		  print_man_foot(struct termp *, const void *);
 static	void		  print_bvspace(struct termp *, 
 				const struct man_node *);
 
-static	int		  pre_alternate(DECL_ARGS);
 static	int		  pre_B(DECL_ARGS);
 static	int		  pre_HP(DECL_ARGS);
 static	int		  pre_I(DECL_ARGS);
 static	int		  pre_IP(DECL_ARGS);
+static	int		  pre_OP(DECL_ARGS);
 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_TP(DECL_ARGS);
+static	int		  pre_alternate(DECL_ARGS);
+static	int		  pre_ft(DECL_ARGS);
 static	int		  pre_ign(DECL_ARGS);
 static	int		  pre_in(DECL_ARGS);
 static	int		  pre_literal(DECL_ARGS);
 static	int		  pre_sp(DECL_ARGS);
-static	int		  pre_ft(DECL_ARGS);
 
 static	void		  post_IP(DECL_ARGS);
 static	void		  post_HP(DECL_ARGS);
@@ -126,7 +114,7 @@ static	const struct termact termacts[MAN_MAX] = {
 	{ pre_I, NULL, 0 }, /* I */
 	{ pre_alternate, NULL, 0 }, /* IR */
 	{ pre_alternate, NULL, 0 }, /* RI */
-	{ NULL, NULL, MAN_NOTEXT }, /* na */
+	{ pre_ign, NULL, MAN_NOTEXT }, /* na */
 	{ pre_sp, NULL, MAN_NOTEXT }, /* sp */
 	{ pre_literal, NULL, 0 }, /* nf */
 	{ pre_literal, NULL, 0 }, /* fi */
@@ -138,6 +126,7 @@ static	const struct termact termacts[MAN_MAX] = {
 	{ pre_ign, NULL, 0 }, /* AT */
 	{ pre_in, NULL, MAN_NOTEXT }, /* in */
 	{ pre_ft, NULL, MAN_NOTEXT }, /* ft */
+	{ pre_OP, NULL, 0 }, /* OP */
 };
 
 
@@ -152,19 +141,15 @@ terminal_man(void *arg, const struct man *man)
 
 	p = (struct termp *)arg;
 
+	if (0 == p->defindent)
+		p->defindent = 7;
+
 	p->overstep = 0;
 	p->maxrmargin = p->defrmargin;
 	p->tabwidth = term_len(p, 5);
 
 	if (NULL == p->symtab)
-		switch (p->enc) {
-		case (TERMENC_ASCII):
-			p->symtab = chars_init(CHARS_ASCII);
-			break;
-		default:
-			abort();
-			/* NOTREACHED */
-		}
+		p->symtab = mchars_alloc();
 
 	n = man_node(man);
 	m = man_meta(man);
@@ -172,9 +157,10 @@ terminal_man(void *arg, const struct man *man)
 	term_begin(p, print_man_head, print_man_foot, m);
 	p->flags |= TERMP_NOSPACE;
 
-	mt.fl = 0;
-	mt.lmargin = term_len(p, INDENT);
-	mt.offset = term_len(p, INDENT);
+	memset(&mt, 0, sizeof(struct mtermp));
+
+	mt.lmargin[mt.lmargincur] = term_len(p, p->defindent);
+	mt.offset = term_len(p, p->defindent);
 
 	if (n->child)
 		print_man_nodelist(p, &mt, n->child, m);
@@ -189,7 +175,7 @@ a2height(const struct termp *p, const char *cp)
 	struct roffsu	 su;
 
 	if ( ! a2roffsu(cp, &su, SCALE_VS))
-		SCALE_VS_INIT(&su, term_strlen(p, cp));
+		SCALE_VS_INIT(&su, atoi(cp));
 
 	return(term_vspan(p, &su));
 }
@@ -206,24 +192,31 @@ a2width(const struct termp *p, const char *cp)
 	return((int)term_hspan(p, &su));
 }
 
-
+/*
+ * 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 termp *p, const struct man_node *n)
 {
+
 	term_newln(p);
 
-	if (NULL == n->prev)
-		return;
+	if (n->body && n->body->child)
+		if (MAN_TBL == n->body->child->type)
+			return;
 
-	if (MAN_SS == n->prev->tok)
-		return;
-	if (MAN_SH == n->prev->tok)
-		return;
+	if (MAN_ROOT == n->parent->type || MAN_RS != n->parent->tok)
+		if (NULL == n->prev)
+			return;
 
 	term_vspace(p);
 }
 
-
 /* ARGSUSED */
 static int
 pre_ign(DECL_ARGS)
@@ -255,7 +248,19 @@ pre_literal(DECL_ARGS)
 	else
 		mt->fl &= ~MANT_LITERAL;
 
-	return(1);
+	/*
+	 * Unlike .IP and .TP, .HP does not have a HEAD.
+	 * So in case a second call to term_flushln() is needed,
+	 * indentation has to be set up explicitly.
+	 */
+	if (MAN_HP == n->parent->tok && p->rmargin < p->maxrmargin) {
+		p->offset = p->rmargin;
+		p->rmargin = p->maxrmargin;
+		p->flags &= ~(TERMP_NOBREAK | TERMP_TWOSPACE);
+		p->flags |= TERMP_NOSPACE;
+	}
+
+	return(0);
 }
 
 /* ARGSUSED */
@@ -319,6 +324,29 @@ pre_B(DECL_ARGS)
 	return(1);
 }
 
+/* ARGSUSED */
+static int
+pre_OP(DECL_ARGS)
+{
+
+	term_word(p, "[");
+	p->flags |= TERMP_NOSPACE;
+
+	if (NULL != (n = n->child)) {
+		term_fontrepl(p, TERMFONT_BOLD);
+		term_word(p, n->string);
+	}
+	if (NULL != n && NULL != n->next) {
+		term_fontrepl(p, TERMFONT_UNDER);
+		term_word(p, n->next->string);
+	}
+
+	term_fontrepl(p, TERMFONT_NONE);
+	p->flags |= TERMP_NOSPACE;
+	term_word(p, "]");
+	return(0);
+}
+
 /* ARGSUSED */
 static int
 pre_ft(DECL_ARGS)
@@ -397,6 +425,11 @@ pre_in(DECL_ARGS)
 	else 
 		p->offset = v;
 
+	/* Don't let this creep beyond the right margin. */
+
+	if (p->offset > p->rmargin)
+		p->offset = p->rmargin;
+
 	return(0);
 }
 
@@ -407,6 +440,13 @@ pre_sp(DECL_ARGS)
 {
 	size_t		 i, len;
 
+	if ((NULL == n->prev && n->parent)) {
+		if (MAN_SS == n->parent->tok)
+			return(0);
+		if (MAN_SH == n->parent->tok)
+			return(0);
+	}
+
 	switch (n->tok) {
 	case (MAN_br):
 		len = 0;
@@ -429,7 +469,7 @@ pre_sp(DECL_ARGS)
 static int
 pre_HP(DECL_ARGS)
 {
-	size_t			 len;
+	size_t			 len, one;
 	int			 ival;
 	const struct man_node	*nn;
 
@@ -445,7 +485,7 @@ pre_HP(DECL_ARGS)
 		return(0);
 	}
 
-	len = mt->lmargin;
+	len = mt->lmargin[mt->lmargincur];
 	ival = -1;
 
 	/* Calculate offset. */
@@ -454,14 +494,15 @@ pre_HP(DECL_ARGS)
 		if ((ival = a2width(p, nn->string)) >= 0)
 			len = (size_t)ival;
 
-	if (0 == len)
-		len = term_len(p, 1);
+	one = term_len(p, 1);
+	if (len < one)
+		len = one;
 
 	p->offset = mt->offset;
 	p->rmargin = mt->offset + len;
 
 	if (ival >= 0)
-		mt->lmargin = (size_t)ival;
+		mt->lmargin[mt->lmargincur] = (size_t)ival;
 
 	return(1);
 }
@@ -496,7 +537,7 @@ pre_PP(DECL_ARGS)
 
 	switch (n->type) {
 	case (MAN_BLOCK):
-		mt->lmargin = term_len(p, INDENT);
+		mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
 		print_bvspace(p, n);
 		break;
 	default:
@@ -518,7 +559,6 @@ pre_IP(DECL_ARGS)
 
 	switch (n->type) {
 	case (MAN_BODY):
-		p->flags |= TERMP_NOLPAD;
 		p->flags |= TERMP_NOSPACE;
 		break;
 	case (MAN_HEAD):
@@ -531,7 +571,7 @@ pre_IP(DECL_ARGS)
 		return(1);
 	}
 
-	len = mt->lmargin;
+	len = mt->lmargin[mt->lmargincur];
 	ival = -1;
 
 	/* Calculate the offset from the optional second argument. */
@@ -552,7 +592,7 @@ pre_IP(DECL_ARGS)
 			break;
 
 		/* Set the saved left-margin. */
-		mt->lmargin = (size_t)ival;
+		mt->lmargin[mt->lmargincur] = (size_t)ival;
 
 		savelit = MANT_LITERAL & mt->fl;
 		mt->fl &= ~MANT_LITERAL;
@@ -589,7 +629,6 @@ post_IP(DECL_ARGS)
 		break;
 	case (MAN_BODY):
 		term_newln(p);
-		p->flags &= ~TERMP_NOLPAD;
 		break;
 	default:
 		break;
@@ -610,7 +649,6 @@ pre_TP(DECL_ARGS)
 		p->flags |= TERMP_NOBREAK;
 		break;
 	case (MAN_BODY):
-		p->flags |= TERMP_NOLPAD;
 		p->flags |= TERMP_NOSPACE;
 		break;
 	case (MAN_BLOCK):
@@ -620,18 +658,15 @@ pre_TP(DECL_ARGS)
 		return(1);
 	}
 
-	len = (size_t)mt->lmargin;
+	len = (size_t)mt->lmargin[mt->lmargincur];
 	ival = -1;
 
 	/* Calculate offset. */
 
-	if (NULL != (nn = n->parent->head->child)) {
-		while (nn && MAN_TEXT != nn->type)
-			nn = nn->next;
-		if (nn && nn->next)
+	if (NULL != (nn = n->parent->head->child))
+		if (nn->string && nn->parent->line == nn->line)
 			if ((ival = a2width(p, nn->string)) >= 0)
 				len = (size_t)ival;
-	}
 
 	switch (n->type) {
 	case (MAN_HEAD):
@@ -652,9 +687,8 @@ pre_TP(DECL_ARGS)
 
 		if (savelit)
 			mt->fl |= MANT_LITERAL;
-
 		if (ival >= 0)
-			mt->lmargin = (size_t)ival;
+			mt->lmargin[mt->lmargincur] = (size_t)ival;
 
 		return(0);
 	case (MAN_BODY):
@@ -683,7 +717,6 @@ post_TP(DECL_ARGS)
 		break;
 	case (MAN_BODY):
 		term_newln(p);
-		p->flags &= ~TERMP_NOLPAD;
 		break;
 	default:
 		break;
@@ -698,8 +731,9 @@ pre_SS(DECL_ARGS)
 
 	switch (n->type) {
 	case (MAN_BLOCK):
-		mt->lmargin = term_len(p, INDENT);
-		mt->offset = term_len(p, INDENT);
+		mt->fl &= ~MANT_LITERAL;
+		mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
+		mt->offset = term_len(p, p->defindent);
 		/* If following a prior empty `SS', no vspace. */
 		if (n->prev && MAN_SS == n->prev->tok)
 			if (NULL == n->prev->body->child)
@@ -710,7 +744,7 @@ pre_SS(DECL_ARGS)
 		break;
 	case (MAN_HEAD):
 		term_fontrepl(p, TERMFONT_BOLD);
-		p->offset = term_len(p, HALFINDENT);
+		p->offset = term_len(p, p->defindent/2);
 		break;
 	case (MAN_BODY):
 		p->offset = mt->offset;
@@ -748,8 +782,9 @@ pre_SH(DECL_ARGS)
 
 	switch (n->type) {
 	case (MAN_BLOCK):
-		mt->lmargin = term_len(p, INDENT);
-		mt->offset = term_len(p, INDENT);
+		mt->fl &= ~MANT_LITERAL;
+		mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
+		mt->offset = term_len(p, p->defindent);
 		/* If following a prior empty `SH', no vspace. */
 		if (n->prev && MAN_SH == n->prev->tok)
 			if (NULL == n->prev->body->child)
@@ -791,13 +826,12 @@ post_SH(DECL_ARGS)
 	}
 }
 
-
 /* ARGSUSED */
 static int
 pre_RS(DECL_ARGS)
 {
-	const struct man_node	*nn;
-	int			 ival;
+	int		 ival;
+	size_t		 sz;
 
 	switch (n->type) {
 	case (MAN_BLOCK):
@@ -809,40 +843,52 @@ pre_RS(DECL_ARGS)
 		break;
 	}
 
-	if (NULL == (nn = n->parent->head->child)) {
-		mt->offset = mt->lmargin + term_len(p, INDENT);
-		p->offset = mt->offset;
-		return(1);
-	}
+	sz = term_len(p, p->defindent);
 
-	if ((ival = a2width(p, nn->string)) < 0)
-		return(1);
+	if (NULL != (n = n->parent->head->child))
+		if ((ival = a2width(p, n->string)) >= 0) 
+			sz = (size_t)ival;
 
-	mt->offset = term_len(p, INDENT) + (size_t)ival;
-	p->offset = mt->offset;
+	mt->offset += sz;
+	p->rmargin = p->maxrmargin;
+	p->offset = mt->offset < p->rmargin ? mt->offset : p->rmargin;
 
+	if (++mt->lmarginsz < MAXMARGINS)
+		mt->lmargincur = mt->lmarginsz;
+
+	mt->lmargin[mt->lmargincur] = mt->lmargin[mt->lmargincur - 1];
 	return(1);
 }
 
-
 /* ARGSUSED */
 static void
 post_RS(DECL_ARGS)
 {
+	int		 ival;
+	size_t		 sz;
 
 	switch (n->type) {
 	case (MAN_BLOCK):
-		mt->offset = mt->lmargin = term_len(p, INDENT);
-		break;
+		return;
 	case (MAN_HEAD):
-		break;
+		return;
 	default:
 		term_newln(p);
-		p->offset = term_len(p, INDENT);
 		break;
 	}
-}
 
+	sz = term_len(p, p->defindent);
+
+	if (NULL != (n = n->parent->head->child)) 
+		if ((ival = a2width(p, n->string)) >= 0) 
+			sz = (size_t)ival;
+
+	mt->offset = mt->offset < sz ?  0 : mt->offset - sz;
+	p->offset = mt->offset;
+
+	if (--mt->lmarginsz < MAXMARGINS)
+		mt->lmargincur = mt->lmarginsz;
+}
 
 static void
 print_man_node(DECL_ARGS)
@@ -850,58 +896,73 @@ print_man_node(DECL_ARGS)
 	size_t		 rm, rmax;
 	int		 c;
 
-	c = 1;
-
 	switch (n->type) {
 	case(MAN_TEXT):
-		if (0 == *n->string) {
+		/*
+		 * If we have a blank line, output a vertical space.
+		 * If we have a space as the first character, break
+		 * before printing the line's data.
+		 */
+		if ('\0' == *n->string) {
 			term_vspace(p);
-			break;
-		}
+			return;
+		} else if (' ' == *n->string && MAN_LINE & n->flags)
+			term_newln(p);
 
 		term_word(p, n->string);
 
-		/* FIXME: this means that macro lines are munged!  */
-
-		if (MANT_LITERAL & mt->fl) {
+		/*
+		 * If we're in a literal context, make sure that words
+		 * togehter on the same line stay together.  This is a
+		 * POST-printing call, so we check the NEXT word.  Since
+		 * -man doesn't have nested macros, we don't need to be
+		 * more specific than this.
+		 */
+		if (MANT_LITERAL & mt->fl && ! (TERMP_NOBREAK & p->flags) &&
+				(NULL == n->next || 
+				 n->next->line > n->line)) {
 			rm = p->rmargin;
 			rmax = p->maxrmargin;
 			p->rmargin = p->maxrmargin = TERM_MAXMARGIN;
 			p->flags |= TERMP_NOSPACE;
 			term_flushln(p);
-			p->flags &= ~TERMP_NOLPAD;
 			p->rmargin = rm;
 			p->maxrmargin = rmax;
 		}
-		break;
+
+		if (MAN_EOS & n->flags)
+			p->flags |= TERMP_SENTENCE;
+		return;
+	case (MAN_EQN):
+		term_eqn(p, n->eqn);
+		return;
 	case (MAN_TBL):
+		/*
+		 * Tables are preceded by a newline.  Then process a
+		 * table line, which will cause line termination,
+		 */
 		if (TBL_SPAN_FIRST & n->span->flags) 
 			term_newln(p);
 		term_tbl(p, n->span);
-		break;
+		return;
 	default:
-		if ( ! (MAN_NOTEXT & termacts[n->tok].flags))
-			term_fontrepl(p, TERMFONT_NONE);
-		if (termacts[n->tok].pre)
-			c = (*termacts[n->tok].pre)(p, mt, n, m);
 		break;
 	}
 
+	if ( ! (MAN_NOTEXT & termacts[n->tok].flags))
+		term_fontrepl(p, TERMFONT_NONE);
+
+	c = 1;
+	if (termacts[n->tok].pre)
+		c = (*termacts[n->tok].pre)(p, mt, n, m);
+
 	if (c && n->child)
 		print_man_nodelist(p, mt, n->child, m);
 
-	switch (n->type) {
-	case (MAN_TEXT):
-		/* FALLTHROUGH */
-	case (MAN_TBL):
-		break;
-	default:
-		if (termacts[n->tok].post)
-			(*termacts[n->tok].post)(p, mt, n, m);
-		if ( ! (MAN_NOTEXT & termacts[n->tok].flags))
-			term_fontrepl(p, TERMFONT_NONE);
-		break;
-	}
+	if (termacts[n->tok].post)
+		(*termacts[n->tok].post)(p, mt, n, m);
+	if ( ! (MAN_NOTEXT & termacts[n->tok].flags))
+		term_fontrepl(p, TERMFONT_NONE);
 
 	if (MAN_EOS & n->flags)
 		p->flags |= TERMP_SENTENCE;
@@ -922,42 +983,65 @@ print_man_nodelist(DECL_ARGS)
 static void
 print_man_foot(struct termp *p, const void *arg)
 {
-	char		buf[DATESIZ];
+	char		title[BUFSIZ];
+	size_t		datelen;
 	const struct man_meta *meta;
 
 	meta = (const struct man_meta *)arg;
+	assert(meta->title);
+	assert(meta->msec);
+	assert(meta->date);
 
 	term_fontrepl(p, TERMFONT_NONE);
 
-	if (meta->rawdate)
-		strlcpy(buf, meta->rawdate, DATESIZ);
-	else
-		time2a(meta->date, buf, DATESIZ);
+	term_vspace(p);
 
-	term_vspace(p);
-	term_vspace(p);
-	term_vspace(p);
+	/*
+	 * Temporary, undocumented option to imitate mdoc(7) output.
+	 * In the bottom right corner, use the source instead of
+	 * the title.
+	 */
+
+	if ( ! p->mdocstyle) {
+		term_vspace(p);
+		term_vspace(p);
+		snprintf(title, BUFSIZ, "%s(%s)", meta->title, meta->msec);
+	} else if (meta->source) {
+		strlcpy(title, meta->source, BUFSIZ);
+	} else {
+		title[0] = '\0';
+	}
+	datelen = term_strlen(p, meta->date);
+
+	/* Bottom left corner: manual source. */
 
 	p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
-	p->rmargin = p->maxrmargin - term_strlen(p, buf);
 	p->offset = 0;
-
-	/* term_strlen() can return zero. */
-	if (p->rmargin == p->maxrmargin)
-		p->rmargin--;
+	p->rmargin = (p->maxrmargin - datelen + term_len(p, 1)) / 2;
 
 	if (meta->source)
 		term_word(p, meta->source);
-	if (meta->source)
-		term_word(p, "");
 	term_flushln(p);
 
-	p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
+	/* At the bottom in the middle: manual date. */
+
+	p->flags |= TERMP_NOSPACE;
+	p->offset = p->rmargin;
+	p->rmargin = p->maxrmargin - term_strlen(p, title);
+	if (p->offset + datelen >= p->rmargin)
+		p->rmargin = p->offset + datelen;
+
+	term_word(p, meta->date);
+	term_flushln(p);
+
+	/* Bottom right corner: manual title and section. */
+
+	p->flags &= ~TERMP_NOBREAK;
+	p->flags |= TERMP_NOSPACE;
 	p->offset = p->rmargin;
 	p->rmargin = p->maxrmargin;
-	p->flags &= ~TERMP_NOBREAK;
 
-	term_word(p, buf);
+	term_word(p, title);
 	term_flushln(p);
 }
 
@@ -970,36 +1054,33 @@ print_man_head(struct termp *p, const void *arg)
 	const struct man_meta *m;
 
 	m = (const struct man_meta *)arg;
-
-	/*
-	 * Note that old groff would spit out some spaces before the
-	 * header.  We discontinue this strange behaviour, but at one
-	 * point we did so here.
-	 */
-
-	p->rmargin = p->maxrmargin;
-
-	p->offset = 0;
-	buf[0] = title[0] = '\0';
+	assert(m->title);
+	assert(m->msec);
 
 	if (m->vol)
 		strlcpy(buf, m->vol, BUFSIZ);
+	else
+		buf[0] = '\0';
 	buflen = term_strlen(p, buf);
 
+	/* Top left corner: manual title and section. */
+
 	snprintf(title, BUFSIZ, "%s(%s)", m->title, m->msec);
 	titlen = term_strlen(p, title);
 
+	p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
 	p->offset = 0;
 	p->rmargin = 2 * (titlen+1) + buflen < p->maxrmargin ?
 	    (p->maxrmargin - 
 	     term_strlen(p, buf) + term_len(p, 1)) / 2 :
 	    p->maxrmargin - buflen;
-	p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
 
 	term_word(p, title);
 	term_flushln(p);
 
-	p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
+	/* At the top in the middle: manual volume. */
+
+	p->flags |= TERMP_NOSPACE;
 	p->offset = p->rmargin;
 	p->rmargin = p->offset + buflen + titlen < p->maxrmargin ?
 	    p->maxrmargin - titlen : p->maxrmargin;
@@ -1007,25 +1088,30 @@ print_man_head(struct termp *p, const void *arg)
 	term_word(p, buf);
 	term_flushln(p);
 
+	/* Top right corner: title and section, again. */
+
 	p->flags &= ~TERMP_NOBREAK;
 	if (p->rmargin + titlen <= p->maxrmargin) {
-		p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
+		p->flags |= TERMP_NOSPACE;
 		p->offset = p->rmargin;
 		p->rmargin = p->maxrmargin;
 		term_word(p, title);
 		term_flushln(p);
 	}
 
-	p->rmargin = p->maxrmargin;
-	p->offset = 0;
 	p->flags &= ~TERMP_NOSPACE;
+	p->offset = 0;
+	p->rmargin = p->maxrmargin;
 
 	/* 
-	 * Groff likes to have some leading spaces before content.  Well
-	 * that's fine by me.
+	 * Groff prints three blank lines before the content.
+	 * Do the same, except in the temporary, undocumented
+	 * mode imitating mdoc(7) output.
 	 */
 
 	term_vspace(p);
-	term_vspace(p);
-	term_vspace(p);
+	if ( ! p->mdocstyle) {
+		term_vspace(p);
+		term_vspace(p);
+	}
 }
diff --git a/external/bsd/mdocml/dist/man_validate.c b/external/bsd/mdocml/dist/man_validate.c
index 095ee67df..cf3a30e1e 100644
--- a/external/bsd/mdocml/dist/man_validate.c
+++ b/external/bsd/mdocml/dist/man_validate.c
@@ -1,6 +1,7 @@
-/*	$Vendor-Id: man_validate.c,v 1.57 2011/01/01 12:59:17 kristaps Exp $ */
+/*	$Vendor-Id: man_validate.c,v 1.80 2012/01/03 15:16:24 kristaps Exp $ */
 /*
- * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons 
+ * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons 
+ * Copyright (c) 2010 Ingo Schwarze 
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -29,6 +30,7 @@
 #include 
 #include 
 
+#include "man.h"
 #include "mandoc.h"
 #include "libman.h"
 #include "libmandoc.h"
@@ -42,50 +44,52 @@ struct	man_valid {
 	v_check	 *posts;
 };
 
-static	int	  check_bline(CHKARGS);
 static	int	  check_eq0(CHKARGS);
-static	int	  check_ft(CHKARGS);
+static	int	  check_eq2(CHKARGS);
 static	int	  check_le1(CHKARGS);
 static	int	  check_ge2(CHKARGS);
 static	int	  check_le5(CHKARGS);
 static	int	  check_par(CHKARGS);
 static	int	  check_part(CHKARGS);
 static	int	  check_root(CHKARGS);
-static	int	  check_sec(CHKARGS);
-static	int	  check_text(CHKARGS);
-static	int	  check_title(CHKARGS);
+static	void	  check_text(CHKARGS);
 
 static	int	  post_AT(CHKARGS);
+static	int	  post_vs(CHKARGS);
 static	int	  post_fi(CHKARGS);
+static	int	  post_ft(CHKARGS);
 static	int	  post_nf(CHKARGS);
+static	int	  post_sec(CHKARGS);
 static	int	  post_TH(CHKARGS);
 static	int	  post_UC(CHKARGS);
+static	int	  pre_sec(CHKARGS);
 
 static	v_check	  posts_at[] = { post_AT, NULL };
+static	v_check	  posts_br[] = { post_vs, check_eq0, NULL };
 static	v_check	  posts_eq0[] = { check_eq0, NULL };
+static	v_check	  posts_eq2[] = { check_eq2, NULL };
 static	v_check	  posts_fi[] = { check_eq0, post_fi, NULL };
-static	v_check	  posts_le1[] = { check_le1, NULL };
-static	v_check	  posts_ft[] = { check_ft, NULL };
+static	v_check	  posts_ft[] = { post_ft, NULL };
 static	v_check	  posts_nf[] = { check_eq0, post_nf, NULL };
 static	v_check	  posts_par[] = { check_par, NULL };
 static	v_check	  posts_part[] = { check_part, NULL };
-static	v_check	  posts_sec[] = { check_sec, NULL };
-static	v_check	  posts_th[] = { check_ge2, check_le5, check_title, post_TH, NULL };
+static	v_check	  posts_sec[] = { post_sec, NULL };
+static	v_check	  posts_sp[] = { post_vs, check_le1, NULL };
+static	v_check	  posts_th[] = { check_ge2, check_le5, post_TH, NULL };
 static	v_check	  posts_uc[] = { post_UC, NULL };
-static	v_check	  pres_bline[] = { check_bline, NULL };
-
+static	v_check	  pres_sec[] = { pre_sec, NULL };
 
 static	const struct man_valid man_valids[MAN_MAX] = {
-	{ NULL, posts_eq0 }, /* br */
-	{ pres_bline, posts_th }, /* TH */
-	{ pres_bline, posts_sec }, /* SH */
-	{ pres_bline, posts_sec }, /* SS */
-	{ pres_bline, posts_par }, /* TP */
-	{ pres_bline, posts_par }, /* LP */
-	{ pres_bline, posts_par }, /* PP */
-	{ pres_bline, posts_par }, /* P */
-	{ pres_bline, posts_par }, /* IP */
-	{ pres_bline, posts_par }, /* HP */
+	{ NULL, posts_br }, /* br */
+	{ NULL, posts_th }, /* TH */
+	{ pres_sec, posts_sec }, /* SH */
+	{ pres_sec, posts_sec }, /* SS */
+	{ NULL, NULL }, /* TP */
+	{ NULL, posts_par }, /* LP */
+	{ NULL, posts_par }, /* PP */
+	{ NULL, posts_par }, /* P */
+	{ NULL, NULL }, /* IP */
+	{ NULL, NULL }, /* HP */
 	{ NULL, NULL }, /* SM */
 	{ NULL, NULL }, /* SB */
 	{ NULL, NULL }, /* BI */
@@ -97,10 +101,10 @@ static	const struct man_valid man_valids[MAN_MAX] = {
 	{ NULL, NULL }, /* I */
 	{ NULL, NULL }, /* IR */
 	{ NULL, NULL }, /* RI */
-	{ NULL, posts_eq0 }, /* na */ /* FIXME: should warn only. */
-	{ NULL, posts_le1 }, /* sp */ /* FIXME: should warn only. */
-	{ pres_bline, posts_nf }, /* nf */
-	{ pres_bline, posts_fi }, /* fi */
+	{ NULL, posts_eq0 }, /* na */
+	{ NULL, posts_sp }, /* sp */
+	{ NULL, posts_nf }, /* nf */
+	{ NULL, posts_fi }, /* fi */
 	{ NULL, NULL }, /* RE */
 	{ NULL, posts_part }, /* RS */
 	{ NULL, NULL }, /* DT */
@@ -109,6 +113,7 @@ static	const struct man_valid man_valids[MAN_MAX] = {
 	{ NULL, posts_at }, /* AT */
 	{ NULL, NULL }, /* in */
 	{ NULL, posts_ft }, /* ft */
+	{ NULL, posts_eq2 }, /* OP */
 };
 
 
@@ -122,6 +127,8 @@ man_valid_pre(struct man *m, struct man_node *n)
 		/* FALLTHROUGH */
 	case (MAN_ROOT):
 		/* FALLTHROUGH */
+	case (MAN_EQN):
+		/* FALLTHROUGH */
 	case (MAN_TBL):
 		return(1);
 	default:
@@ -148,9 +155,12 @@ man_valid_post(struct man *m)
 
 	switch (m->last->type) {
 	case (MAN_TEXT): 
-		return(check_text(m, m->last));
+		check_text(m, m->last);
+		return(1);
 	case (MAN_ROOT):
 		return(check_root(m, m->last));
+	case (MAN_EQN):
+		/* FALLTHROUGH */
 	case (MAN_TBL):
 		return(1);
 	default:
@@ -191,94 +201,47 @@ check_root(CHKARGS)
 		 */
 
 	        m->meta.title = mandoc_strdup("unknown");
-		m->meta.date = time(NULL);
 		m->meta.msec = mandoc_strdup("1");
+		m->meta.date = mandoc_normdate
+			(m->parse, NULL, n->line, n->pos);
 	}
 
 	return(1);
 }
 
-
-static int
-check_title(CHKARGS) 
+static void
+check_text(CHKARGS)
 {
-	const char	*p;
+	char		*cp, *p;
 
-	assert(n->child);
-	/* FIXME: is this sufficient? */
-	if ('\0' == *n->child->string) {
-		man_nmsg(m, n, MANDOCERR_SYNTARGCOUNT);
-		return(0);
-	}
+	if (MAN_LITERAL & m->flags)
+		return;
 
-	for (p = n->child->string; '\0' != *p; p++)
-		/* Only warn about this once... */
-		if (isalpha((u_char)*p) && ! isupper((u_char)*p)) {
-			man_nmsg(m, n, MANDOCERR_UPPERCASE);
-			break;
-		}
-
-	return(1);
+	cp = n->string;
+	for (p = cp; NULL != (p = strchr(p, '\t')); p++)
+		man_pmsg(m, n->line, (int)(p - cp), MANDOCERR_BADTAB);
 }
 
-
-static int
-check_text(CHKARGS) 
-{
-	char		*p;
-	int		 pos, c;
-	size_t		 sz;
-
-	for (p = n->string, pos = n->pos + 1; *p; p++, pos++) {
-		sz = strcspn(p, "\t\\");
-		p += (int)sz;
-
-		if ('\0' == *p)
-			break;
-
-		pos += (int)sz;
-
-		if ('\t' == *p) {
-			if (MAN_LITERAL & m->flags)
-				continue;
-			if (man_pmsg(m, n->line, pos, MANDOCERR_BADTAB))
-				continue;
-			return(0);
-		}
-
-		/* Check the special character. */
-
-		c = mandoc_special(p);
-		if (c) {
-			p += c - 1;
-			pos += c - 1;
-		} else
-			man_pmsg(m, n->line, pos, MANDOCERR_BADESCAPE);
-	}
-
-	return(1);
-}
-
-
 #define	INEQ_DEFINE(x, ineq, name) \
 static int \
 check_##name(CHKARGS) \
 { \
 	if (n->nchild ineq (x)) \
 		return(1); \
-	man_vmsg(m, MANDOCERR_SYNTARGCOUNT, n->line, n->pos, \
+	mandoc_vmsg(MANDOCERR_ARGCOUNT, m->parse, n->line, n->pos, \
 			"line arguments %s %d (have %d)", \
 			#ineq, (x), n->nchild); \
-	return(0); \
+	return(1); \
 }
 
 INEQ_DEFINE(0, ==, eq0)
+INEQ_DEFINE(2, ==, eq2)
 INEQ_DEFINE(1, <=, le1)
 INEQ_DEFINE(2, >=, ge2)
 INEQ_DEFINE(5, <=, le5)
 
 static int
-check_ft(CHKARGS)
+post_ft(CHKARGS)
 {
 	char	*cp;
 	int	 ok;
@@ -318,38 +281,48 @@ check_ft(CHKARGS)
 	}
 
 	if (0 == ok) {
-		man_vmsg(m, MANDOCERR_BADFONT, 
-				n->line, n->pos, "%s", cp);
+		mandoc_vmsg
+			(MANDOCERR_BADFONT, m->parse,
+			 n->line, n->pos, "%s", cp);
 		*cp = '\0';
 	}
 
 	if (1 < n->nchild)
-		man_vmsg(m, MANDOCERR_ARGCOUNT, n->line, n->pos,
-				"want one child (have %d)", n->nchild);
+		mandoc_vmsg
+			(MANDOCERR_ARGCOUNT, m->parse, n->line, 
+			 n->pos, "want one child (have %d)", 
+			 n->nchild);
 
 	return(1);
 }
 
 static int
-check_sec(CHKARGS)
+pre_sec(CHKARGS)
 {
 
-	if (MAN_HEAD == n->type && 0 == n->nchild) {
-		man_nmsg(m, n, MANDOCERR_SYNTARGCOUNT);
-		return(0);
-	} else if (MAN_BODY == n->type && 0 == n->nchild)
-		man_nmsg(m, n, MANDOCERR_NOBODY);
-
+	if (MAN_BLOCK == n->type)
+		m->flags &= ~MAN_LITERAL;
 	return(1);
 }
 
+static int
+post_sec(CHKARGS)
+{
+
+	if ( ! (MAN_HEAD == n->type && 0 == n->nchild)) 
+		return(1);
+
+	man_nmsg(m, n, MANDOCERR_SYNTARGCOUNT);
+	return(0);
+}
 
 static int
 check_part(CHKARGS)
 {
 
 	if (MAN_BODY == n->type && 0 == n->nchild)
-		man_nmsg(m, n, MANDOCERR_NOBODY);
+		mandoc_msg(MANDOCERR_ARGCWARN, m->parse, n->line, 
+				n->pos, "want children (have none)");
 
 	return(1);
 }
@@ -359,54 +332,32 @@ static int
 check_par(CHKARGS)
 {
 
-	if (MAN_BODY == n->type) 
-		switch (n->tok) {
-		case (MAN_IP):
-			/* FALLTHROUGH */
-		case (MAN_HP):
-			/* FALLTHROUGH */
-		case (MAN_TP):
-			/* Body-less lists are ok. */
-			break;
-		default:
-			if (0 == n->nchild)
-				man_nmsg(m, n, MANDOCERR_NOBODY);
-			break;
-		}
-	if (MAN_HEAD == n->type)
-		switch (n->tok) {
-		case (MAN_PP):
-			/* FALLTHROUGH */
-		case (MAN_P):
-			/* FALLTHROUGH */
-		case (MAN_LP):
-			if (n->nchild)
-				man_nmsg(m, n, MANDOCERR_ARGSLOST);
-			break;
-		default:
-			break;
-		}
-
-	return(1);
-}
-
-
-static int
-check_bline(CHKARGS)
-{
-
-	assert( ! (MAN_ELINE & m->flags));
-	if (MAN_BLINE & m->flags) {
-		man_nmsg(m, n, MANDOCERR_SYNTLINESCOPE);
-		return(0);
+	switch (n->type) {
+	case (MAN_BLOCK):
+		if (0 == n->body->nchild)
+			man_node_delete(m, n);
+		break;
+	case (MAN_BODY):
+		if (0 == n->nchild)
+			man_nmsg(m, n, MANDOCERR_IGNPAR);
+		break;
+	case (MAN_HEAD):
+		if (n->nchild)
+			man_nmsg(m, n, MANDOCERR_ARGSLOST);
+		break;
+	default:
+		break;
 	}
 
 	return(1);
 }
 
+
 static int
 post_TH(CHKARGS)
 {
+	const char	*p;
+	int		 line, pos;
 
 	if (m->meta.title)
 		free(m->meta.title);
@@ -416,44 +367,49 @@ post_TH(CHKARGS)
 		free(m->meta.source);
 	if (m->meta.msec)
 		free(m->meta.msec);
-	if (m->meta.rawdate)
-		free(m->meta.rawdate);
+	if (m->meta.date)
+		free(m->meta.date);
 
-	m->meta.title = m->meta.vol = m->meta.rawdate =
+	line = n->line;
+	pos = n->pos;
+	m->meta.title = m->meta.vol = m->meta.date =
 		m->meta.msec = m->meta.source = NULL;
-	m->meta.date = 0;
 
 	/* ->TITLE<- MSEC DATE SOURCE VOL */
 
 	n = n->child;
-	assert(n);
-	m->meta.title = mandoc_strdup(n->string);
+	if (n && n->string) {
+		for (p = n->string; '\0' != *p; p++) {
+			/* Only warn about this once... */
+			if (isalpha((unsigned char)*p) && 
+					! isupper((unsigned char)*p)) {
+				man_nmsg(m, n, MANDOCERR_UPPERCASE);
+				break;
+			}
+		}
+		m->meta.title = mandoc_strdup(n->string);
+	} else
+		m->meta.title = mandoc_strdup("");
 
 	/* TITLE ->MSEC<- DATE SOURCE VOL */
 
-	n = n->next;
-	assert(n);
-	m->meta.msec = mandoc_strdup(n->string);
+	if (n)
+		n = n->next;
+	if (n && n->string)
+		m->meta.msec = mandoc_strdup(n->string);
+	else
+		m->meta.msec = mandoc_strdup("");
 
 	/* TITLE MSEC ->DATE<- SOURCE VOL */
 
-	/*
-	 * Try to parse the date.  If this works, stash the epoch (this
-	 * is optimal because we can reformat it in the canonical form).
-	 * If it doesn't parse, isn't specified at all, or is an empty
-	 * string, then use the current date.
-	 */
-
-	n = n->next;
-	if (n && n->string && *n->string) {
-		m->meta.date = mandoc_a2time
-			(MTIME_ISO_8601, n->string);
-		if (0 == m->meta.date) {
-			man_nmsg(m, n, MANDOCERR_BADDATE);
-			m->meta.rawdate = mandoc_strdup(n->string);
-		}
+	if (n)
+		n = n->next;
+	if (n && n->string && '\0' != n->string[0]) {
+		pos = n->pos;
+		m->meta.date = mandoc_normdate
+		    (m->parse, n->string, line, pos);
 	} else
-		m->meta.date = time(NULL);
+		m->meta.date = mandoc_strdup("");
 
 	/* TITLE MSEC DATE ->SOURCE<- VOL */
 
@@ -461,9 +417,13 @@ post_TH(CHKARGS)
 		m->meta.source = mandoc_strdup(n->string);
 
 	/* TITLE MSEC DATE SOURCE ->VOL<- */
+	/* If missing, use the default VOL name for MSEC. */
 
 	if (n && (n = n->next))
 		m->meta.vol = mandoc_strdup(n->string);
+	else if ('\0' != m->meta.msec[0] &&
+	    (NULL != (p = mandoc_a2msec(m->meta.msec))))
+		m->meta.vol = mandoc_strdup(p);
 
 	/*
 	 * Remove the `TH' node after we've processed it for our
@@ -489,7 +449,7 @@ post_fi(CHKARGS)
 {
 
 	if ( ! (MAN_LITERAL & m->flags))
-		man_nmsg(m, n, MANDOCERR_NOSCOPE);
+		man_nmsg(m, n, MANDOCERR_WNOSCOPE);
 
 	m->flags &= ~MAN_LITERAL;
 	return(1);
@@ -509,7 +469,6 @@ post_UC(CHKARGS)
 	const char	*p, *s;
 
 	n = n->child;
-	n = m->last->child;
 
 	if (NULL == n || MAN_TEXT != n->type)
 		p = bsd_versions[0];
@@ -575,3 +534,17 @@ post_AT(CHKARGS)
 	m->meta.source = mandoc_strdup(p);
 	return(1);
 }
+
+static int
+post_vs(CHKARGS)
+{
+
+	/* 
+	 * Don't warn about this because it occurs in pod2man and would
+	 * cause considerable (unfixable) warnage.
+	 */
+	if (NULL == n->prev && MAN_ROOT == n->parent->type)
+		man_node_delete(m, n);
+
+	return(1);
+}
diff --git a/external/bsd/mdocml/dist/mandoc b/external/bsd/mdocml/dist/mandoc
deleted file mode 100755
index b62a209174fb66f051705b5743dfaaf3b557e802..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 725594
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
    +#giCgk8~5^_a^9~* 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%0DXQv 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 o1{K5%RPvzl2fVBO$TgtJ5AV}%Tl)1 +.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons .\" .\" 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 January 4, 2011 +.Dd December 25, 2011 .Dt MANDOC 1 .Os .Sh NAME @@ -27,13 +27,26 @@ .Op Fl O Ns Ar option .Op Fl T Ns Ar output .Op Fl W Ns Ar level -.Op Ar file... +.Op Ar .Sh DESCRIPTION The .Nm utility formats .Ux manual pages for display. +.Pp +By default, +.Nm +reads +.Xr mdoc 7 +or +.Xr man 7 +text from stdin, implying +.Fl m Ns Cm andoc , +and produces +.Fl T Ns Cm ascii +output. +.Pp The arguments are as follows: .Bl -tag -width Ds .It Fl m Ns Ar format @@ -96,18 +109,6 @@ If multiple files are specified, .Nm will halt with the first failed parse. .El -.Pp -By default, -.Nm -reads -.Xr mdoc 7 -or -.Xr man 7 -text from stdin, implying -.Fl m Ns Cm andoc , -and produces -.Fl T Ns Cm ascii -output. .Ss Input Formats The .Nm @@ -157,7 +158,7 @@ The utility accepts the following .Fl T arguments, which correspond to output modes: -.Bl -tag -width Ds +.Bl -tag -width "-Tlocale" .It Fl T Ns Cm ascii Produce 7-bit ASCII output. This is the default. @@ -171,6 +172,16 @@ See Parse only: produce no output. Implies .Fl W Ns Cm warning . +.It Fl T Ns Cm locale +Encode output using the current locale. +See +.Sx Locale Output . +.It Fl T Ns Cm man +Produce +.Xr man 7 +format output. +See +.Sx Man Output . .It Fl T Ns Cm pdf Produce PDF output. See @@ -181,6 +192,10 @@ See .Sx PostScript Output . .It Fl T Ns Cm tree Produce an indented parse tree. +.It Fl T Ns Cm utf8 +Encode output in the UTF\-8 multi-byte format. +See +.Sx UTF\-8 Output . .It Fl T Ns Cm xhtml Produce strict CSS1/XHTML-1.0 output. See @@ -209,6 +224,9 @@ Emboldened characters are rendered as The special characters documented in .Xr mandoc_char 7 are rendered best-effort in an ASCII equivalent. +If no equivalent is found, +.Sq \&? +is used instead. .Pp Output width is limited to 78 visible columns unless literal input lines exceed this limit. @@ -217,6 +235,15 @@ The following .Fl O arguments are accepted: .Bl -tag -width Ds +.It Cm indent Ns = Ns Ar indent +The left margin for normal text is set to +.Ar indent +blank characters instead of the default of five for +.Xr mdoc 7 +and seven for +.Xr man 7 . +Increasing this is not recommended; it may result in degraded formatting, +for example overfull lines or ugly line breaks. .It Cm width Ns = Ns Ar width The output width is set to .Ar width , @@ -236,12 +263,27 @@ If a style-sheet is not specified with defaults to simple output readable in any graphical or text-based web browser. .Pp -Special characters are rendered in decimal-encoded UTF-8. +Special characters are rendered in decimal-encoded UTF\-8. .Pp The following .Fl O arguments are accepted: .Bl -tag -width Ds +.It Cm fragment +Omit the +.Aq !DOCTYPE +declaration and the +.Aq html , +.Aq head , +and +.Aq body +elements and only emit the subtree below the +.Aq body +element. +The +.Cm style +argument will be ignored. +This is useful when embedding manual content within existing documents. .It Cm includes Ns = Ns Ar fmt The string .Ar fmt , @@ -278,6 +320,48 @@ is used for an external style-sheet. This must be a valid absolute or relative URI. .El +.Ss Locale Output +Locale-depending output encoding is triggered with +.Fl T Ns Cm locale . +This option is not available on all systems: systems without locale +support, or those whose internal representation is not natively UCS-4, +will fall back to +.Fl T Ns Cm ascii . +See +.Sx ASCII Output +for font style specification and available command-line arguments. +.Ss Man Output +Translate input format into +.Xr man 7 +output format. +This is useful for distributing manual sources to legancy systems +lacking +.Xr mdoc 7 +formatters. +.Pp +If +.Xr mdoc 7 +is passed as input, it is translated into +.Xr man 7 . +If the input format is +.Xr man 7 , +the input is copied to the output, expanding any +.Xr roff 7 +.Sq so +requests. +The parser is also run, and as usual, the +.Fl W +level controls which +.Sx DIAGNOSTICS +are displayed before copying the input to the output. +.Ss PDF Output +PDF-1.1 output may be generated by +.Fl T Ns Cm pdf . +See +.Sx PostScript Output +for +.Fl O +arguments and defaults. .Ss PostScript Output PostScript .Qq Adobe-3.0 @@ -312,14 +396,13 @@ If an unknown value is encountered, .Ar letter is used. .El -.Ss PDF Output -PDF-1.1 output may be generated by -.Fl T Ns Cm pdf . +.Ss UTF\-8 Output +Use +.Fl T Ns Cm utf8 +to force a UTF\-8 locale. See -.Sx PostScript Output -for -.Fl O -arguments and defaults. +.Sx Locale Output +for details and options. .Ss XHTML Output Output produced by .Fl T Ns Cm xhtml @@ -389,6 +472,16 @@ To check over a large set of manuals: To produce a series of PostScript manuals for A4 paper: .Pp .Dl $ mandoc \-Tps \-Opaper=a4 mdoc.7 man.7 \*(Gt manuals.ps +.Pp +Convert a modern +.Xr mdoc 7 +manual to the older +.Xr man 7 +format, for use on systems lacking an +.Xr mdoc 7 +parser: +.Pp +.Dl $ mandoc \-Tman foo.mdoc \*(Gt foo.man .Sh DIAGNOSTICS Standard error messages reporting parsing errors are prefixed by .Pp @@ -460,6 +553,13 @@ Each input and output format is separately noted. .Ss ASCII Compatibility .Bl -bullet -compact .It +Unrenderable unicode codepoints specified with +.Sq \e[uNNNN] +escapes are printed as +.Sq \&? +in mandoc. +In GNU troff, these raise an error. +.It The .Sq \&Bd \-literal and @@ -470,7 +570,7 @@ in .Fl T Ns Cm ascii are synonyms, as are \-filled and \-ragged. .It -In GNU troff, the +In historic GNU troff, the .Sq \&Pa .Xr mdoc 7 macro does not underline when scoped under an @@ -495,8 +595,6 @@ macro in has no effect. .It Words aren't hyphenated. -.It -Sentences are unilaterally monospaced. .El .Ss HTML/XHTML Compatibility .Bl -bullet -compact @@ -529,6 +627,7 @@ and lists render similarly. .El .Sh SEE ALSO +.Xr eqn 7 , .Xr man 7 , .Xr mandoc_char 7 , .Xr mdoc 7 , @@ -538,7 +637,8 @@ lists render similarly. The .Nm utility was written by -.An Kristaps Dzonsons Aq kristaps@bsd.lv . +.An Kristaps Dzonsons , +.Mt kristaps@bsd.lv . .Sh CAVEATS In .Fl T Ns Cm html diff --git a/external/bsd/mdocml/dist/mandoc.3 b/external/bsd/mdocml/dist/mandoc.3 new file mode 100644 index 000000000..11329674b --- /dev/null +++ b/external/bsd/mdocml/dist/mandoc.3 @@ -0,0 +1,600 @@ +.\" $Vendor-Id: mandoc.3,v 1.17 2012/01/13 15:27:14 joerg Exp $ +.\" +.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons +.\" Copyright (c) 2010 Ingo Schwarze +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd January 13, 2012 +.Dt MANDOC 3 +.Os +.Sh NAME +.Nm mandoc , +.Nm mandoc_escape , +.Nm man_meta , +.Nm man_mparse , +.Nm man_node , +.Nm mchars_alloc , +.Nm mchars_free , +.Nm mchars_num2char , +.Nm mchars_num2uc , +.Nm mchars_spec2cp , +.Nm mchars_spec2str , +.Nm mdoc_meta , +.Nm mdoc_node , +.Nm mparse_alloc , +.Nm mparse_free , +.Nm mparse_getkeep , +.Nm mparse_keep , +.Nm mparse_readfd , +.Nm mparse_reset , +.Nm mparse_result , +.Nm mparse_strerror , +.Nm mparse_strlevel +.Nd mandoc macro compiler library +.Sh LIBRARY +.Lb mandoc +.Sh SYNOPSIS +.In man.h +.In mdoc.h +.In mandoc.h +.Ft "enum mandoc_esc" +.Fo mandoc_escape +.Fa "const char **end" +.Fa "const char **start" +.Fa "int *sz" +.Fc +.Ft "const struct man_meta *" +.Fo man_meta +.Fa "const struct man *man" +.Fc +.Ft "const struct mparse *" +.Fo man_mparse +.Fa "const struct man *man" +.Fc +.Ft "const struct man_node *" +.Fo man_node +.Fa "const struct man *man" +.Fc +.Ft "struct mchars *" +.Fn mchars_alloc +.Ft void +.Fn mchars_free "struct mchars *p" +.Ft char +.Fn mchars_num2char "const char *cp" "size_t sz" +.Ft int +.Fn mchars_num2uc "const char *cp" "size_t sz" +.Ft "const char *" +.Fo mchars_spec2str +.Fa "const struct mchars *p" +.Fa "const char *cp" +.Fa "size_t sz" +.Fa "size_t *rsz" +.Fc +.Ft int +.Fo mchars_spec2cp +.Fa "const struct mchars *p" +.Fa "const char *cp" +.Fa "size_t sz" +.Ft "const char *" +.Fc +.Ft "const struct mdoc_meta *" +.Fo mdoc_meta +.Fa "const struct mdoc *mdoc" +.Fc +.Ft "const struct mdoc_node *" +.Fo mdoc_node +.Fa "const struct mdoc *mdoc" +.Fc +.Ft void +.Fo mparse_alloc +.Fa "enum mparset type" +.Fa "enum mandoclevel wlevel" +.Fa "mandocmsg msg" +.Fa "void *msgarg" +.Fc +.Ft void +.Fo mparse_free +.Fa "struct mparse *parse" +.Fc +.Ft void +.Fo mparse_getkeep +.Fa "const struct mparse *parse" +.Fc +.Ft void +.Fo mparse_keep +.Fa "struct mparse *parse" +.Fc +.Ft "enum mandoclevel" +.Fo mparse_readfd +.Fa "struct mparse *parse" +.Fa "int fd" +.Fa "const char *fname" +.Fc +.Ft void +.Fo mparse_reset +.Fa "struct mparse *parse" +.Fc +.Ft void +.Fo mparse_result +.Fa "struct mparse *parse" +.Fa "struct mdoc **mdoc" +.Fa "struct man **man" +.Fc +.Ft "const char *" +.Fo mparse_strerror +.Fa "enum mandocerr" +.Fc +.Ft "const char *" +.Fo mparse_strlevel +.Fa "enum mandoclevel" +.Fc +.Vt extern const char * const * man_macronames; +.Vt extern const char * const * mdoc_argnames; +.Vt extern const char * const * mdoc_macronames; +.Fd "#define ASCII_NBRSP" +.Fd "#define ASCII_HYPH" +.Sh DESCRIPTION +The +.Nm mandoc +library parses a +.Ux +manual into an abstract syntax tree (AST). +.Ux +manuals are composed of +.Xr mdoc 7 +or +.Xr man 7 , +and may be mixed with +.Xr roff 7 , +.Xr tbl 7 , +and +.Xr eqn 7 +invocations. +.Pp +The following describes a general parse sequence: +.Bl -enum +.It +initiate a parsing sequence with +.Fn mparse_alloc ; +.It +parse files or file descriptors with +.Fn mparse_readfd ; +.It +retrieve a parsed syntax tree, if the parse was successful, with +.Fn mparse_result ; +.It +iterate over parse nodes with +.Fn mdoc_node +or +.Fn man_node ; +.It +free all allocated memory with +.Fn mparse_free , +or invoke +.Fn mparse_reset +and parse new files. +.El +.Pp +The +.Nm +library also contains routines for translating character strings into glyphs +.Pq see Fn mchars_alloc +and parsing escape sequences from strings +.Pq see Fn mandoc_escape . +.Sh REFERENCE +This section documents the functions, types, and variables available +via +.In mandoc.h . +.Ss Types +.Bl -ohang +.It Vt "enum mandoc_esc" +An escape sequence classification. +.It Vt "enum mandocerr" +A fatal error, error, or warning message during parsing. +.It Vt "enum mandoclevel" +A classification of an +.Vt "enum mandoclevel" +as regards system operation. +.It Vt "struct mchars" +An opaque pointer to an object allowing for translation between +character strings and glyphs. +See +.Fn mchars_alloc . +.It Vt "enum mparset" +The type of parser when reading input. +This should usually be +.Dv MPARSE_AUTO +for auto-detection. +.It Vt "struct mparse" +An opaque pointer to a running parse sequence. +Created with +.Fn mparse_alloc +and freed with +.Fn mparse_free . +This may be used across parsed input if +.Fn mparse_reset +is called between parses. +.It Vt "mandocmsg" +A prototype for a function to handle fatal error, error, and warning +messages emitted by the parser. +.El +.Ss Functions +.Bl -ohang +.It Fn mandoc_escape +Scan an escape sequence, i.e., a character string beginning with +.Sq \e . +Pass a pointer to the character after the +.Sq \e +as +.Va end ; +it will be set to the supremum of the parsed escape sequence unless +returning +.Dv ESCAPE_ERROR , +in which case the string is bogus and should be +thrown away. +If not +.Dv ESCAPE_ERROR +or +.Dv ESCAPE_IGNORE , +.Va start +is set to the first relevant character of the substring (font, glyph, +whatever) of length +.Va sz . +Both +.Va start +and +.Va sz +may be +.Dv NULL . +.It Fn man_meta +Obtain the meta-data of a successful parse. +This may only be used on a pointer returned by +.Fn mparse_result . +.It Fn man_mparse +Get the parser used for the current output. +.It Fn man_node +Obtain the root node of a successful parse. +This may only be used on a pointer returned by +.Fn mparse_result . +.It Fn mchars_alloc +Allocate an +.Vt "struct mchars *" +object for translating special characters into glyphs. +See +.Xr mandoc_char 7 +for an overview of special characters. +The object must be freed with +.Fn mchars_free . +.It Fn mchars_free +Free an object created with +.Fn mchars_alloc . +.It Fn mchars_num2char +Convert a character index (e.g., the \eN\(aq\(aq escape) into a +printable ASCII character. +Returns \e0 (the nil character) if the input sequence is malformed. +.It Fn mchars_num2uc +Convert a hexadecimal character index (e.g., the \e[uNNNN] escape) into +a Unicode codepoint. +Returns \e0 (the nil character) if the input sequence is malformed. +.It Fn mchars_spec2cp +Convert a special character into a valid Unicode codepoint. +Returns \-1 on failure or a non-zero Unicode codepoint on success. +.It Fn mchars_spec2str +Convert a special character into an ASCII string. +Returns +.Dv NULL +on failure. +.It Fn mdoc_meta +Obtain the meta-data of a successful parse. +This may only be used on a pointer returned by +.Fn mparse_result . +.It Fn mdoc_node +Obtain the root node of a successful parse. +This may only be used on a pointer returned by +.Fn mparse_result . +.It Fn mparse_alloc +Allocate a parser. +The same parser may be used for multiple files so long as +.Fn mparse_reset +is called between parses. +.Fn mparse_free +must be called to free the memory allocated by this function. +.It Fn mparse_free +Free all memory allocated by +.Fn mparse_alloc . +.It Fn mparse_getkeep +Acquire the keep buffer. +Must follow a call of +.Fn mparse_keep . +.It Fn mparse_keep +Instruct the parser to retain a copy of its parsed input. +This can be acquired with subsequent +.Fn mparse_getkeep +calls. +.It Fn mparse_readfd +Parse a file or file descriptor. +If +.Va fd +is -1, +.Va fname +is opened for reading. +Otherwise, +.Va fname +is assumed to be the name associated with +.Va fd . +This may be called multiple times with different parameters; however, +.Fn mparse_reset +should be invoked between parses. +.It Fn mparse_reset +Reset a parser so that +.Fn mparse_readfd +may be used again. +.It Fn mparse_result +Obtain the result of a parse. +Only successful parses +.Po +i.e., those where +.Fn mparse_readfd +returned less than MANDOCLEVEL_FATAL +.Pc +should invoke this function, in which case one of the two pointers will +be filled in. +.It Fn mparse_strerror +Return a statically-allocated string representation of an error code. +.It Fn mparse_strlevel +Return a statically-allocated string representation of a level code. +.El +.Ss Variables +.Bl -ohang +.It Va man_macronames +The string representation of a man macro as indexed by +.Vt "enum mant" . +.It Va mdoc_argnames +The string representation of a mdoc macro argument as indexed by +.Vt "enum mdocargt" . +.It Va mdoc_macronames +The string representation of a mdoc macro as indexed by +.Vt "enum mdoct" . +.El +.Sh IMPLEMENTATION NOTES +This section consists of structural documentation for +.Xr mdoc 7 +and +.Xr man 7 +syntax trees and strings. +.Ss Man and Mdoc Strings +Strings may be extracted from mdoc and man meta-data, or from text +nodes (MDOC_TEXT and MAN_TEXT, respectively). +These strings have special non-printing formatting cues embedded in the +text itself, as well as +.Xr roff 7 +escapes preserved from input. +Implementing systems will need to handle both situations to produce +human-readable text. +In general, strings may be assumed to consist of 7-bit ASCII characters. +.Pp +The following non-printing characters may be embedded in text strings: +.Bl -tag -width Ds +.It Dv ASCII_NBRSP +A non-breaking space character. +.It Dv ASCII_HYPH +A soft hyphen. +.El +.Pp +Escape characters are also passed verbatim into text strings. +An escape character is a sequence of characters beginning with the +backslash +.Pq Sq \e . +To construct human-readable text, these should be intercepted with +.Fn mandoc_escape +and converted with one of +.Fn mchars_num2char , +.Fn mchars_spec2str , +and so on. +.Ss Man Abstract Syntax Tree +This AST is governed by the ontological rules dictated in +.Xr man 7 +and derives its terminology accordingly. +.Pp +The AST is composed of +.Vt struct man_node +nodes with element, root and text types as declared by the +.Va type +field. +Each node also provides its parse point (the +.Va line , +.Va sec , +and +.Va pos +fields), its position in the tree (the +.Va parent , +.Va child , +.Va next +and +.Va prev +fields) and some type-specific data. +.Pp +The tree itself is arranged according to the following normal form, +where capitalised non-terminals represent nodes. +.Pp +.Bl -tag -width "ELEMENTXX" -compact +.It ROOT +\(<- mnode+ +.It mnode +\(<- ELEMENT | TEXT | BLOCK +.It BLOCK +\(<- HEAD BODY +.It HEAD +\(<- mnode* +.It BODY +\(<- mnode* +.It ELEMENT +\(<- ELEMENT | TEXT* +.It TEXT +\(<- [[:ascii:]]* +.El +.Pp +The only elements capable of nesting other elements are those with +next-lint scope as documented in +.Xr man 7 . +.Ss Mdoc Abstract Syntax Tree +This AST is governed by the ontological +rules dictated in +.Xr mdoc 7 +and derives its terminology accordingly. +.Qq In-line +elements described in +.Xr mdoc 7 +are described simply as +.Qq elements . +.Pp +The AST is composed of +.Vt struct mdoc_node +nodes with block, head, body, element, root and text types as declared +by the +.Va type +field. +Each node also provides its parse point (the +.Va line , +.Va sec , +and +.Va pos +fields), its position in the tree (the +.Va parent , +.Va child , +.Va nchild , +.Va next +and +.Va prev +fields) and some type-specific data, in particular, for nodes generated +from macros, the generating macro in the +.Va tok +field. +.Pp +The tree itself is arranged according to the following normal form, +where capitalised non-terminals represent nodes. +.Pp +.Bl -tag -width "ELEMENTXX" -compact +.It ROOT +\(<- mnode+ +.It mnode +\(<- BLOCK | ELEMENT | TEXT +.It BLOCK +\(<- HEAD [TEXT] (BODY [TEXT])+ [TAIL [TEXT]] +.It ELEMENT +\(<- TEXT* +.It HEAD +\(<- mnode* +.It BODY +\(<- mnode* [ENDBODY mnode*] +.It TAIL +\(<- mnode* +.It TEXT +\(<- [[:ascii:]]* +.El +.Pp +Of note are the TEXT nodes following the HEAD, BODY and TAIL nodes of +the BLOCK production: these refer to punctuation marks. +Furthermore, although a TEXT node will generally have a non-zero-length +string, in the specific case of +.Sq \&.Bd \-literal , +an empty line will produce a zero-length string. +Multiple body parts are only found in invocations of +.Sq \&Bl \-column , +where a new body introduces a new phrase. +.Pp +The +.Xr mdoc 7 +syntax tree accommodates for broken block structures as well. +The ENDBODY node is available to end the formatting associated +with a given block before the physical end of that block. +It has a non-null +.Va end +field, is of the BODY +.Va type , +has the same +.Va tok +as the BLOCK it is ending, and has a +.Va pending +field pointing to that BLOCK's BODY node. +It is an indirect child of that BODY node +and has no children of its own. +.Pp +An ENDBODY node is generated when a block ends while one of its child +blocks is still open, like in the following example: +.Bd -literal -offset indent +\&.Ao ao +\&.Bo bo ac +\&.Ac bc +\&.Bc end +.Ed +.Pp +This example results in the following block structure: +.Bd -literal -offset indent +BLOCK Ao + HEAD Ao + BODY Ao + TEXT ao + BLOCK Bo, pending -> Ao + HEAD Bo + BODY Bo + TEXT bo + TEXT ac + ENDBODY Ao, pending -> Ao + TEXT bc +TEXT end +.Ed +.Pp +Here, the formatting of the +.Sq \&Ao +block extends from TEXT ao to TEXT ac, +while the formatting of the +.Sq \&Bo +block extends from TEXT bo to TEXT bc. +It renders as follows in +.Fl T Ns Cm ascii +mode: +.Pp +.Dl bc] end +.Pp +Support for badly-nested blocks is only provided for backward +compatibility with some older +.Xr mdoc 7 +implementations. +Using badly-nested blocks is +.Em strongly discouraged ; +for example, the +.Fl T Ns Cm html +and +.Fl T Ns Cm xhtml +front-ends to +.Xr mandoc 1 +are unable to render them in any meaningful way. +Furthermore, behaviour when encountering badly-nested blocks is not +consistent across troff implementations, especially when using multiple +levels of badly-nested blocks. +.Sh SEE ALSO +.Xr mandoc 1 , +.Xr eqn 7 , +.Xr man 7 , +.Xr mandoc_char 7 , +.Xr mdoc 7 , +.Xr roff 7 , +.Xr tbl 7 +.Sh AUTHORS +The +.Nm +library was written by +.An Kristaps Dzonsons , +.Mt kristaps@bsd.lv . diff --git a/external/bsd/mdocml/dist/mandoc.c b/external/bsd/mdocml/dist/mandoc.c index e6f7971c6..e9b5c68c6 100644 --- a/external/bsd/mdocml/dist/mandoc.c +++ b/external/bsd/mdocml/dist/mandoc.c @@ -1,6 +1,6 @@ -/* $Vendor-Id: mandoc.c,v 1.36 2011/01/03 22:42:37 schwarze Exp $ */ +/* $Vendor-Id: mandoc.c,v 1.62 2011/12/03 16:08:51 schwarze Exp $ */ /* - * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons * Copyright (c) 2011 Ingo Schwarze * * Permission to use, copy, modify, and distribute this software for any @@ -23,6 +23,8 @@ #include #include +#include +#include #include #include #include @@ -31,200 +33,384 @@ #include "mandoc.h" #include "libmandoc.h" +#define DATESIZE 32 + static int a2time(time_t *, const char *, const char *); +static char *time2a(time_t); +static int numescape(const char *); - -int -mandoc_special(char *p) +/* + * Pass over recursive numerical expressions. This context of this + * function is important: it's only called within character-terminating + * escapes (e.g., \s[xxxyyy]), so all we need to do is handle initial + * recursion: we don't care about what's in these blocks. + * This returns the number of characters skipped or -1 if an error + * occurs (the caller should bail). + */ +static int +numescape(const char *start) { - int len, i; - char term; - char *sv; - - len = 0; - term = '\0'; - sv = p; + int i; + size_t sz; + const char *cp; - assert('\\' == *p); - p++; + i = 0; - switch (*p++) { -#if 0 - case ('Z'): - /* FALLTHROUGH */ - case ('X'): - /* FALLTHROUGH */ - case ('x'): - /* FALLTHROUGH */ - case ('S'): - /* FALLTHROUGH */ - case ('R'): - /* FALLTHROUGH */ - case ('N'): - /* FALLTHROUGH */ - case ('l'): - /* FALLTHROUGH */ - case ('L'): - /* FALLTHROUGH */ - case ('H'): - /* FALLTHROUGH */ - case ('h'): - /* FALLTHROUGH */ - case ('D'): - /* FALLTHROUGH */ + /* The expression consists of a subexpression. */ + + if ('\\' == start[i]) { + cp = &start[++i]; + /* + * Read past the end of the subexpression. + * Bail immediately on errors. + */ + if (ESCAPE_ERROR == mandoc_escape(&cp, NULL, NULL)) + return(-1); + return(i + cp - &start[i]); + } + + if ('(' != start[i++]) + return(0); + + /* + * A parenthesised subexpression. Read until the closing + * parenthesis, making sure to handle any nested subexpressions + * that might ruin our parse. + */ + + while (')' != start[i]) { + sz = strcspn(&start[i], ")\\"); + i += (int)sz; + + if ('\0' == start[i]) + return(-1); + else if ('\\' != start[i]) + continue; + + cp = &start[++i]; + if (ESCAPE_ERROR == mandoc_escape(&cp, NULL, NULL)) + return(-1); + i += cp - &start[i]; + } + + /* Read past the terminating ')'. */ + return(++i); +} + +enum mandoc_esc +mandoc_escape(const char **end, const char **start, int *sz) +{ + char c, term, numeric; + int i, lim, ssz, rlim; + const char *cp, *rstart; + enum mandoc_esc gly; + + cp = *end; + rstart = cp; + if (start) + *start = rstart; + i = lim = 0; + gly = ESCAPE_ERROR; + term = numeric = '\0'; + + switch ((c = cp[i++])) { + /* + * First the glyphs. There are several different forms of + * these, but each eventually returns a substring of the glyph + * name. + */ + case ('('): + gly = ESCAPE_SPECIAL; + lim = 2; + break; + case ('['): + gly = ESCAPE_SPECIAL; + /* + * Unicode escapes are defined in groff as \[uXXXX] to + * \[u10FFFF], where the contained value must be a valid + * Unicode codepoint. Here, however, only check whether + * it's not a zero-width escape. + */ + if ('u' == cp[i] && ']' != cp[i + 1]) + gly = ESCAPE_UNICODE; + term = ']'; + break; case ('C'): - /* FALLTHROUGH */ - case ('b'): - /* FALLTHROUGH */ - case ('B'): - /* FALLTHROUGH */ - case ('a'): - /* FALLTHROUGH */ - case ('A'): - if (*p++ != '\'') - return(0); + if ('\'' != cp[i]) + return(ESCAPE_ERROR); + gly = ESCAPE_SPECIAL; term = '\''; break; -#endif - case ('h'): + + /* + * Handle all triggers matching \X(xy, \Xx, and \X[xxxx], where + * 'X' is the trigger. These have opaque sub-strings. + */ + case ('F'): /* FALLTHROUGH */ - case ('v'): + case ('g'): /* FALLTHROUGH */ - case ('s'): - if (ASCII_HYPH == *p) - *p = '-'; - - i = 0; - if ('+' == *p || '-' == *p) { - p++; - i = 1; - } - - switch (*p++) { - case ('('): - len = 2; - break; - case ('['): - term = ']'; - break; - case ('\''): - term = '\''; - break; - case ('0'): - i = 1; - /* FALLTHROUGH */ - default: - len = 1; - p--; - break; - } - - if (ASCII_HYPH == *p) - *p = '-'; - if ('+' == *p || '-' == *p) { - if (i) - return(0); - p++; - } - - /* Handle embedded numerical subexp or escape. */ - - if ('(' == *p) { - while (*p && ')' != *p) - if ('\\' == *p++) { - i = mandoc_special(--p); - if (0 == i) - return(0); - p += i; - } - - if (')' == *p++) - break; - - return(0); - } else if ('\\' == *p) { - if (0 == (i = mandoc_special(p))) - return(0); - p += i; - } - - break; -#if 0 - case ('Y'): - /* FALLTHROUGH */ - case ('V'): - /* FALLTHROUGH */ - case ('$'): - /* FALLTHROUGH */ - case ('n'): - /* FALLTHROUGH */ -#endif case ('k'): /* FALLTHROUGH */ case ('M'): /* FALLTHROUGH */ case ('m'): /* FALLTHROUGH */ + case ('n'): + /* FALLTHROUGH */ + case ('V'): + /* FALLTHROUGH */ + case ('Y'): + gly = ESCAPE_IGNORE; + /* FALLTHROUGH */ case ('f'): - /* FALLTHROUGH */ - case ('F'): - /* FALLTHROUGH */ - case ('*'): - switch (*p++) { + if (ESCAPE_ERROR == gly) + gly = ESCAPE_FONT; + + rstart= &cp[i]; + if (start) + *start = rstart; + + switch (cp[i++]) { case ('('): - len = 2; + lim = 2; break; case ('['): term = ']'; break; default: - len = 1; - p--; + lim = 1; + i--; break; } break; - case ('('): - len = 2; - break; - case ('['): - term = ']'; - break; - case ('z'): - len = 1; - if ('\\' == *p) { - if (0 == (i = mandoc_special(p))) - return(0); - p += i; - return(*p ? (int)(p - sv) : 0); - } - break; + + /* + * These escapes are of the form \X'Y', where 'X' is the trigger + * and 'Y' is any string. These have opaque sub-strings. + */ + case ('A'): + /* FALLTHROUGH */ + case ('b'): + /* FALLTHROUGH */ + case ('D'): + /* FALLTHROUGH */ case ('o'): /* FALLTHROUGH */ + case ('R'): + /* FALLTHROUGH */ + case ('X'): + /* FALLTHROUGH */ + case ('Z'): + if ('\'' != cp[i++]) + return(ESCAPE_ERROR); + gly = ESCAPE_IGNORE; + term = '\''; + break; + + /* + * These escapes are of the form \X'N', where 'X' is the trigger + * and 'N' resolves to a numerical expression. + */ + case ('B'): + /* FALLTHROUGH */ + case ('h'): + /* FALLTHROUGH */ + case ('H'): + /* FALLTHROUGH */ + case ('L'): + /* FALLTHROUGH */ + case ('l'): + gly = ESCAPE_NUMBERED; + /* FALLTHROUGH */ + case ('S'): + /* FALLTHROUGH */ + case ('v'): + /* FALLTHROUGH */ case ('w'): - if ('\'' == *p++) { - term = '\''; + /* FALLTHROUGH */ + case ('x'): + if (ESCAPE_ERROR == gly) + gly = ESCAPE_IGNORE; + if ('\'' != cp[i++]) + return(ESCAPE_ERROR); + term = numeric = '\''; + break; + + /* + * Special handling for the numbered character escape. + * XXX Do any other escapes need similar handling? + */ + case ('N'): + if ('\0' == cp[i]) + return(ESCAPE_ERROR); + *end = &cp[++i]; + if (isdigit((unsigned char)cp[i-1])) + return(ESCAPE_IGNORE); + while (isdigit((unsigned char)**end)) + (*end)++; + if (start) + *start = &cp[i]; + if (sz) + *sz = *end - &cp[i]; + if ('\0' != **end) + (*end)++; + return(ESCAPE_NUMBERED); + + /* + * Sizes get a special category of their own. + */ + case ('s'): + gly = ESCAPE_IGNORE; + + rstart = &cp[i]; + if (start) + *start = rstart; + + /* See +/- counts as a sign. */ + c = cp[i]; + if ('+' == c || '-' == c || ASCII_HYPH == c) + ++i; + + switch (cp[i++]) { + case ('('): + lim = 2; + break; + case ('['): + term = numeric = ']'; + break; + case ('\''): + term = numeric = '\''; + break; + default: + lim = 1; + i--; break; } - /* FALLTHROUGH */ + + /* See +/- counts as a sign. */ + c = cp[i]; + if ('+' == c || '-' == c || ASCII_HYPH == c) + ++i; + + break; + + /* + * Anything else is assumed to be a glyph. + */ default: - len = 1; - p--; + gly = ESCAPE_SPECIAL; + lim = 1; + i--; break; } - if (term) { - for ( ; *p && term != *p; p++) - if (ASCII_HYPH == *p) - *p = '-'; - return(*p ? (int)(p - sv) : 0); + assert(ESCAPE_ERROR != gly); + + rstart = &cp[i]; + if (start) + *start = rstart; + + /* + * If a terminating block has been specified, we need to + * handle the case of recursion, which could have their + * own terminating blocks that mess up our parse. This, by the + * way, means that the "start" and "size" values will be + * effectively meaningless. + */ + + ssz = 0; + if (numeric && -1 == (ssz = numescape(&cp[i]))) + return(ESCAPE_ERROR); + + i += ssz; + rlim = -1; + + /* + * We have a character terminator. Try to read up to that + * character. If we can't (i.e., we hit the nil), then return + * an error; if we can, calculate our length, read past the + * terminating character, and exit. + */ + + if ('\0' != term) { + *end = strchr(&cp[i], term); + if ('\0' == *end) + return(ESCAPE_ERROR); + + rlim = *end - &cp[i]; + if (sz) + *sz = rlim; + (*end)++; + goto out; } - for (i = 0; *p && i < len; i++, p++) - if (ASCII_HYPH == *p) - *p = '-'; - return(i == len ? (int)(p - sv) : 0); -} + assert(lim > 0); + /* + * We have a numeric limit. If the string is shorter than that, + * stop and return an error. Else adjust our endpoint, length, + * and return the current glyph. + */ + + if ((size_t)lim > strlen(&cp[i])) + return(ESCAPE_ERROR); + + rlim = lim; + if (sz) + *sz = rlim; + + *end = &cp[i] + lim; + +out: + assert(rlim >= 0 && rstart); + + /* Run post-processors. */ + + switch (gly) { + case (ESCAPE_FONT): + /* + * Pretend that the constant-width font modes are the + * same as the regular font modes. + */ + if (2 == rlim && 'C' == *rstart) + rstart++; + else if (1 != rlim) + break; + + switch (*rstart) { + case ('3'): + /* FALLTHROUGH */ + case ('B'): + gly = ESCAPE_FONTBOLD; + break; + case ('2'): + /* FALLTHROUGH */ + case ('I'): + gly = ESCAPE_FONTITALIC; + break; + case ('P'): + gly = ESCAPE_FONTPREV; + break; + case ('1'): + /* FALLTHROUGH */ + case ('R'): + gly = ESCAPE_FONTROMAN; + break; + } + break; + case (ESCAPE_SPECIAL): + if (1 != rlim) + break; + if ('c' == *rstart) + gly = ESCAPE_NOSPACE; + break; + default: + break; + } + + return(gly); +} void * mandoc_calloc(size_t num, size_t size) @@ -269,6 +455,16 @@ mandoc_realloc(void *ptr, size_t size) return(ptr); } +char * +mandoc_strndup(const char *ptr, size_t sz) +{ + char *p; + + p = mandoc_malloc(sz + 1); + memcpy(p, ptr, sz); + p[(int)sz] = '\0'; + return(p); +} char * mandoc_strdup(const char *ptr) @@ -294,18 +490,18 @@ mandoc_strdup(const char *ptr) * or to the null byte terminating the argument line. */ char * -mandoc_getarg(char **cpp, mandocmsg msg, void *data, int ln, int *pos) +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++; - } else - quoted = 0; + } pairs = 0; white = 0; @@ -341,8 +537,8 @@ mandoc_getarg(char **cpp, mandocmsg msg, void *data, int ln, int *pos) } /* Quoted argument without a closing quote. */ - if (1 == quoted && msg) - (*msg)(MANDOCERR_BADQUOTE, data, ln, *pos, NULL); + if (1 == quoted) + mandoc_msg(MANDOCERR_BADQUOTE, parse, ln, *pos, NULL); /* Null-terminate this argument and move to the next one. */ if (pairs) @@ -352,16 +548,15 @@ mandoc_getarg(char **cpp, mandocmsg msg, void *data, int ln, int *pos) while (' ' == *cp) cp++; } - *pos += (cp - start) + (quoted ? 1 : 0); + *pos += (int)(cp - start) + (quoted ? 1 : 0); *cpp = cp; - if ('\0' == *cp && msg && (white || ' ' == cp[-1])) - (*msg)(MANDOCERR_EOLNSPACE, data, ln, *pos, NULL); + if ('\0' == *cp && (white || ' ' == cp[-1])) + mandoc_msg(MANDOCERR_EOLNSPACE, parse, ln, *pos, NULL); return(start); } - static int a2time(time_t *t, const char *fmt, const char *p) { @@ -370,7 +565,10 @@ a2time(time_t *t, const char *fmt, const char *p) memset(&tm, 0, sizeof(struct tm)); + pp = NULL; +#ifdef HAVE_STRPTIME pp = strptime(p, fmt, &tm); +#endif if (NULL != pp && '\0' == *pp) { *t = mktime(&tm); return(1); @@ -379,41 +577,62 @@ a2time(time_t *t, const char *fmt, const char *p) return(0); } - -/* - * Convert from a manual date string (see mdoc(7) and man(7)) into a - * date according to the stipulated date type. - */ -time_t -mandoc_a2time(int flags, const char *p) +static char * +time2a(time_t t) { - time_t t; + struct tm *tm; + char *buf, *p; + size_t ssz; + int isz; - if (MTIME_MDOCDATE & flags) { - if (0 == strcmp(p, "$" "Mdocdate$")) - return(time(NULL)); - if (a2time(&t, "$" "Mdocdate: %b %d %Y $", p)) - return(t); - } + tm = localtime(&t); - if (MTIME_CANONICAL & flags || MTIME_REDUCED & flags) - if (a2time(&t, "%b %d, %Y", p)) - return(t); + /* + * Reserve space: + * up to 9 characters for the month (September) + blank + * up to 2 characters for the day + comma + blank + * 4 characters for the year and a terminating '\0' + */ + p = buf = mandoc_malloc(10 + 4 + 4 + 1); - if (MTIME_ISO_8601 & flags) - if (a2time(&t, "%Y-%m-%d", p)) - return(t); + if (0 == (ssz = strftime(p, 10 + 1, "%B ", tm))) + goto fail; + p += (int)ssz; - if (MTIME_REDUCED & flags) { - if (a2time(&t, "%d, %Y", p)) - return(t); - if (a2time(&t, "%Y", p)) - return(t); - } + if (-1 == (isz = snprintf(p, 4 + 1, "%d, ", tm->tm_mday))) + goto fail; + p += isz; - return(0); + if (0 == strftime(p, 4 + 1, "%Y", tm)) + goto fail; + return(buf); + +fail: + free(buf); + return(NULL); } +char * +mandoc_normdate(struct mparse *parse, char *in, int ln, int pos) +{ + char *out; + time_t t; + + if (NULL == in || '\0' == *in || + 0 == strcmp(in, "$" "Mdocdate$")) { + mandoc_msg(MANDOCERR_NODATE, parse, ln, pos, NULL); + time(&t); + } + else if (a2time(&t, "%Y-%m-%d", in)) + t = 0; + else if (!a2time(&t, "$" "Mdocdate: %b %d %Y $", in) && + !a2time(&t, "%b %d, %Y", in)) { + mandoc_msg(MANDOCERR_BADDATE, parse, ln, pos, NULL); + t = 0; + } + out = t ? time2a(t) : NULL; + return(out ? out : mandoc_strdup(in)); +} int mandoc_eos(const char *p, size_t sz, int enclosed) @@ -427,7 +646,7 @@ mandoc_eos(const char *p, size_t sz, int enclosed) /* * End-of-sentence recognition must include situations where * some symbols, such as `)', allow prior EOS punctuation to - * propogate outward. + * propagate outward. */ found = 0; @@ -458,30 +677,59 @@ mandoc_eos(const char *p, size_t sz, int enclosed) return(found && !enclosed); } - +/* + * Find out whether a line is a macro line or not. If it is, adjust the + * current position and return one; if it isn't, return zero and don't + * change the current position. + */ int -mandoc_hyph(const char *start, const char *c) +mandoc_getcontrol(const char *cp, int *ppos) { + int pos; - /* - * Choose whether to break at a hyphenated character. We only - * do this if it's free-standing within a word. - */ + pos = *ppos; - /* Skip first/last character of buffer. */ - if (c == start || '\0' == *(c + 1)) - return(0); - /* Skip first/last character of word. */ - if ('\t' == *(c + 1) || '\t' == *(c - 1)) - return(0); - if (' ' == *(c + 1) || ' ' == *(c - 1)) - return(0); - /* Skip double invocations. */ - if ('-' == *(c + 1) || '-' == *(c - 1)) - return(0); - /* Skip escapes. */ - if ('\\' == *(c - 1)) + if ('\\' == cp[pos] && '.' == cp[pos + 1]) + pos += 2; + else if ('.' == cp[pos] || '\'' == cp[pos]) + pos++; + else return(0); + while (' ' == cp[pos] || '\t' == cp[pos]) + pos++; + + *ppos = pos; return(1); } + +/* + * Convert a string to a long that may not be <0. + * If the string is invalid, or is less than 0, return -1. + */ +int +mandoc_strntoi(const char *p, size_t sz, int base) +{ + char buf[32]; + char *ep; + long v; + + if (sz > 31) + return(-1); + + memcpy(buf, p, sz); + buf[(int)sz] = '\0'; + + errno = 0; + v = strtol(buf, &ep, base); + + if (buf[0] == '\0' || *ep != '\0') + return(-1); + + if (v > INT_MAX) + v = INT_MAX; + if (v < INT_MIN) + v = INT_MIN; + + return((int)v); +} diff --git a/external/bsd/mdocml/dist/mandoc.h b/external/bsd/mdocml/dist/mandoc.h index 315273a77..7e94baf34 100644 --- a/external/bsd/mdocml/dist/mandoc.h +++ b/external/bsd/mdocml/dist/mandoc.h @@ -1,4 +1,4 @@ -/* $Vendor-Id: mandoc.h,v 1.49 2011/01/06 13:45:47 kristaps Exp $ */ +/* $Vendor-Id: mandoc.h,v 1.99 2012/02/16 20:51:31 joerg Exp $ */ /* * Copyright (c) 2010, 2011 Kristaps Dzonsons * @@ -50,7 +50,8 @@ enum mandocerr { MANDOCERR_NOTITLE, /* no title in document */ MANDOCERR_UPPERCASE, /* document title should be all caps */ MANDOCERR_BADMSEC, /* unknown manual section */ - MANDOCERR_BADDATE, /* cannot parse date argument */ + MANDOCERR_NODATE, /* date missing, using today's date */ + MANDOCERR_BADDATE, /* cannot parse date, using it verbatim */ MANDOCERR_PROLOGOOO, /* prologue macros out of order */ MANDOCERR_PROLOGREP, /* duplicate prologue macro */ MANDOCERR_BADPROLOG, /* macro not allowed in prologue */ @@ -68,10 +69,12 @@ enum mandocerr { /* related to macros and nesting */ MANDOCERR_MACROOBS, /* skipping obsolete macro */ MANDOCERR_IGNPAR, /* skipping paragraph macro */ + MANDOCERR_IGNNS, /* skipping no-space macro */ MANDOCERR_SCOPENEST, /* blocks badly nested */ MANDOCERR_CHILD, /* child violates parent syntax */ MANDOCERR_NESTEDDISP, /* nested displays are not portable */ MANDOCERR_SCOPEREP, /* already in literal mode */ + MANDOCERR_LINESCOPE, /* line scope broken */ /* related to missing macro arguments */ MANDOCERR_MACROEMPTY, /* skipping empty macro */ @@ -80,6 +83,7 @@ enum mandocerr { MANDOCERR_LISTFIRST, /* list type must come first */ MANDOCERR_NOWIDTHARG, /* tag lists require a width argument */ MANDOCERR_FONTTYPE, /* missing font type */ + MANDOCERR_WNOSCOPE, /* skipping end of block that is not open */ /* related to bad macro arguments */ MANDOCERR_IGNARGV, /* skipping argument */ @@ -100,11 +104,18 @@ enum mandocerr { MANDOCERR_BADESCAPE, /* unknown escape sequence */ MANDOCERR_BADQUOTE, /* unterminated quoted string */ - /* related to tables */ - MANDOCERR_TBLEXTRADAT, /* extra data cells */ + /* related to equations */ + MANDOCERR_EQNQUOTE, /* unexpected literal in equation */ MANDOCERR_ERROR, /* ===== start of errors ===== */ + /* related to equations */ + MANDOCERR_EQNNSCOPE, /* unexpected equation scope closure*/ + MANDOCERR_EQNSCOPE, /* equation scope open on exit */ + MANDOCERR_EQNBADSCOPE, /* overlapping equation scopes */ + MANDOCERR_EQNEOF, /* unexpected end of equation */ + MANDOCERR_EQNSYNT, /* equation syntax error */ + /* related to tables */ MANDOCERR_TBL, /* bad table syntax */ MANDOCERR_TBLOPT, /* bad table option */ @@ -113,13 +124,14 @@ enum mandocerr { MANDOCERR_TBLNODATA, /* no table data cells specified */ MANDOCERR_TBLIGNDATA, /* ignore data in cell */ MANDOCERR_TBLBLOCK, /* data block still open */ + MANDOCERR_TBLEXTRADAT, /* ignoring extra data cells */ MANDOCERR_ROFFLOOP, /* input stack limit exceeded, infinite loop? */ MANDOCERR_BADCHAR, /* skipping bad character */ + MANDOCERR_NAMESC, /* escaped character not allowed in a name */ MANDOCERR_NOTEXT, /* skipping text before the first section header */ MANDOCERR_MACRO, /* skipping unknown macro */ MANDOCERR_REQUEST, /* NOT IMPLEMENTED: skipping request */ - MANDOCERR_LINESCOPE, /* line scope broken */ MANDOCERR_ARGCOUNT, /* argument count wrong */ MANDOCERR_NOSCOPE, /* skipping end of block that is not open */ MANDOCERR_SCOPEBROKEN, /* missing end of block */ @@ -135,9 +147,9 @@ enum mandocerr { MANDOCERR_FATAL, /* ===== start of fatal errors ===== */ + MANDOCERR_NOTMANUAL, /* manual isn't really a manual */ MANDOCERR_COLUMNS, /* column syntax is inconsistent */ MANDOCERR_BADDISP, /* NOT IMPLEMENTED: .Bd -file */ - MANDOCERR_SYNTLINESCOPE, /* line scope broken, syntax violated */ MANDOCERR_SYNTARGVCOUNT, /* argument count wrong, violates syntax */ MANDOCERR_SYNTCHILD, /* child violates parent syntax */ MANDOCERR_SYNTARGCOUNT, /* argument count wrong, violates syntax */ @@ -202,7 +214,7 @@ enum tbl_cellt { struct tbl_cell { struct tbl_cell *next; enum tbl_cellt pos; - int spacing; + size_t spacing; int flags; #define TBL_CELL_TALIGN (1 << 0) /* t, T */ #define TBL_CELL_BALIGN (1 << 1) /* d, D */ @@ -224,12 +236,12 @@ struct tbl_row { }; enum tbl_datt { - TBL_DATA_NONE, - TBL_DATA_DATA, - TBL_DATA_HORIZ, - TBL_DATA_DHORIZ, - TBL_DATA_NHORIZ, - TBL_DATA_NDHORIZ + 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 */ }; /* @@ -237,9 +249,10 @@ enum tbl_datt { * string value that's in the cell. The rest is layout. */ struct tbl_dat { - struct tbl_cell *layout; /* layout cell: CAN BE NULL */ + struct tbl_cell *layout; /* layout cell */ + int spans; /* how many spans follow */ struct tbl_dat *next; - char *string; + char *string; /* data (NULL if not TBL_DATA_DATA) */ enum tbl_datt pos; }; @@ -255,9 +268,10 @@ enum tbl_spant { struct tbl_span { struct tbl *tbl; struct tbl_head *head; - struct tbl_row *layout; /* layout row: CAN BE NULL */ + struct tbl_row *layout; /* layout row */ struct tbl_dat *first; struct tbl_dat *last; + int line; /* parse line */ int flags; #define TBL_SPAN_FIRST (1 << 0) #define TBL_SPAN_LAST (1 << 1) @@ -265,50 +279,153 @@ struct tbl_span { struct tbl_span *next; }; -/* - * Available registers (set in libroff, accessed elsewhere). +enum eqn_boxt { + EQN_ROOT, /* root of parse tree */ + EQN_TEXT, /* text (number, variable, whatever) */ + EQN_SUBEXPR, /* nested `eqn' subexpression */ + EQN_LIST, /* subexpressions list */ + EQN_MATRIX /* matrix subexpression */ +}; + +enum eqn_markt { + EQNMARK_NONE = 0, + EQNMARK_DOT, + EQNMARK_DOTDOT, + EQNMARK_HAT, + EQNMARK_TILDE, + EQNMARK_VEC, + EQNMARK_DYAD, + EQNMARK_BAR, + EQNMARK_UNDER, + EQNMARK__MAX +}; + +enum eqn_fontt { + EQNFONT_NONE = 0, + EQNFONT_ROMAN, + EQNFONT_BOLD, + EQNFONT_FAT, + EQNFONT_ITALIC, + EQNFONT__MAX +}; + +enum eqn_post { + EQNPOS_NONE = 0, + EQNPOS_OVER, + EQNPOS_SUP, + EQNPOS_SUB, + EQNPOS_TO, + EQNPOS_FROM, + EQNPOS__MAX +}; + +enum eqn_pilet { + EQNPILE_NONE = 0, + EQNPILE_PILE, + EQNPILE_CPILE, + EQNPILE_RPILE, + EQNPILE_LPILE, + EQNPILE_COL, + EQNPILE_CCOL, + EQNPILE_RCOL, + EQNPILE_LCOL, + EQNPILE__MAX +}; + + /* + * A "box" is a parsed mathematical expression as defined by the eqn.7 + * grammar. */ -enum regs { - REG_nS = 0, - REG__MAX +struct eqn_box { + int size; /* font size of expression */ +#define EQN_DEFSIZE INT_MIN + enum eqn_boxt type; /* type of node */ + struct eqn_box *first; /* first child node */ + struct eqn_box *last; /* last child node */ + struct eqn_box *next; /* node sibling */ + struct eqn_box *parent; /* node sibling */ + char *text; /* text (or NULL) */ + char *left; + char *right; + enum eqn_post pos; /* position of next box */ + enum eqn_markt mark; /* a mark about the box */ + enum eqn_fontt font; /* font of box */ + enum eqn_pilet pile; /* equation piling */ }; /* - * A register (struct reg) can consist of many types: this consists of - * normalised types from the original string form. + * An equation consists of a tree of expressions starting at a given + * line and position. */ -union regval { - unsigned u; /* unsigned integer */ +struct eqn { + char *name; /* identifier (or NULL) */ + struct eqn_box *root; /* root mathematical expression */ + int ln; /* invocation line */ + int pos; /* invocation position */ }; /* - * A single register entity. If "set" is zero, the value of the - * register should be the default one, which is per-register. It's - * assumed that callers know which type in "v" corresponds to which - * register value. + * The type of parse sequence. This value is usually passed via the + * mandoc(1) command line of -man and -mdoc. It's almost exclusively + * -mandoc but the others have been retained for compatibility. */ -struct reg { - int set; /* whether set or not */ - union regval v; /* parsed data */ +enum mparset { + MPARSE_AUTO, /* magically determine the document type */ + MPARSE_MDOC, /* assume -mdoc */ + MPARSE_MAN /* assume -man */ }; -/* - * The primary interface to setting register values is in libroff, - * although libmdoc and libman from time to time will manipulate - * registers (such as `.Sh SYNOPSIS' enabling REG_nS). - */ -struct regset { - struct reg regs[REG__MAX]; +enum mandoc_esc { + ESCAPE_ERROR = 0, /* bail! unparsable escape */ + ESCAPE_IGNORE, /* escape to be ignored */ + ESCAPE_SPECIAL, /* a regular special character */ + ESCAPE_FONT, /* a generic font mode */ + ESCAPE_FONTBOLD, /* bold font mode */ + ESCAPE_FONTITALIC, /* italic font mode */ + ESCAPE_FONTROMAN, /* roman font mode */ + ESCAPE_FONTPREV, /* previous font mode */ + ESCAPE_NUMBERED, /* a numbered glyph */ + ESCAPE_UNICODE, /* a unicode codepoint */ + ESCAPE_NOSPACE /* suppress space if the last on a line */ }; +typedef void (*mandocmsg)(enum mandocerr, enum mandoclevel, + const char *, int, int, const char *); + +struct mparse; +struct mchars; +struct mdoc; +struct man; + __BEGIN_DECLS -/* - * Callback function for warnings, errors, and fatal errors as they - * occur in the compilers libroff, libmdoc, and libman. - */ -typedef int (*mandocmsg)(enum mandocerr, void *, - int, int, const char *); +void *mandoc_calloc(size_t, size_t); +enum mandoc_esc mandoc_escape(const char **, const char **, int *); +void *mandoc_malloc(size_t); +void *mandoc_realloc(void *, size_t); +char *mandoc_strdup(const char *); +char *mandoc_strndup(const char *, size_t); +struct mchars *mchars_alloc(void); +void mchars_free(struct mchars *); +char mchars_num2char(const char *, size_t); +int mchars_num2uc(const char *, size_t); +int mchars_spec2cp(const struct mchars *, + const char *, size_t); +const char *mchars_spec2str(const struct mchars *, + const char *, size_t, size_t *); +struct mparse *mparse_alloc(enum mparset, + enum mandoclevel, mandocmsg, void *); +void mparse_free(struct mparse *); +void mparse_keep(struct mparse *); +enum mandoclevel mparse_readfd(struct mparse *, int, const char *); +enum mandoclevel mparse_readmem(struct mparse *, const void *, size_t, + const char *); +void mparse_reset(struct mparse *); +void mparse_result(struct mparse *, + struct mdoc **, struct man **); +const char *mparse_getkeep(const struct mparse *); +const char *mparse_strerror(enum mandocerr); +const char *mparse_strlevel(enum mandoclevel); __END_DECLS diff --git a/external/bsd/mdocml/dist/mandoc_char.7 b/external/bsd/mdocml/dist/mandoc_char.7 index a4c5050cf..a5165e0a9 100644 --- a/external/bsd/mdocml/dist/mandoc_char.7 +++ b/external/bsd/mdocml/dist/mandoc_char.7 @@ -1,6 +1,8 @@ -.\" $Vendor-Id: mandoc_char.7,v 1.40 2010/10/29 00:05:53 schwarze Exp $ +.\" $Vendor-Id: mandoc_char.7,v 1.51 2011/11/23 10:09:30 kristaps Exp $ .\" -.\" Copyright (c) 2009 Kristaps Dzonsons +.\" Copyright (c) 2003 Jason McIntyre +.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons +.\" Copyright (c) 2011 Ingo Schwarze .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above @@ -14,26 +16,168 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd October 29, 2010 +.Dd November 23, 2011 .Dt MANDOC_CHAR 7 .Os .Sh NAME .Nm mandoc_char .Nd mandoc special characters .Sh DESCRIPTION -This page documents the special characters and predefined strings accepted by +This page documents the +.Xr roff 7 +escape sequences accepted by .Xr mandoc 1 -to format +to represent special characters in .Xr mdoc 7 and .Xr man 7 documents. .Pp -Both -.Xr mdoc 7 -and -.Xr man 7 -encode special characters with +The rendering depends on the +.Xr mandoc 1 +output mode; in ASCII output, most characters are completely +unintelligible. +For that reason, using any of the special characters documented here, +except those discussed in the +.Sx DESCRIPTION , +is strongly discouraged; they are supported merely for backwards +compatibility with existing documents. +.Pp +In particular, in English manual pages, do not use special-character +escape sequences to represent national language characters in author +names; instead, provide ASCII transcriptions of the names. +.Ss Dashes and Hyphens +In typography there are different types of dashes of various width: +the hyphen (-), +the minus sign (\-), +the en-dash (\(en), +and the em-dash (\(em). +.Pp +Hyphens are used for adjectives; +to separate the two parts of a compound word; +or to separate a word across two successive lines of text. +The hyphen does not need to be escaped: +.Bd -unfilled -offset indent +blue-eyed +lorry-driver +.Ed +.Pp +The mathematical minus sign is used for negative numbers or subtraction. +It should be written as +.Sq \e- : +.Bd -unfilled -offset indent +a = 3 \e- 1; +b = \e-2; +.Ed +.Pp +The en-dash is used to separate the two elements of a range, +or can be used the same way as an em-dash. +It should be written as +.Sq \e(en : +.Bd -unfilled -offset indent +pp. 95\e(en97. +Go away \e(en or else! +.Ed +.Pp +The em-dash can be used to show an interruption +or can be used the same way as colons, semi-colons, or parentheses. +It should be written as +.Sq \e(em : +.Bd -unfilled -offset indent +Three things \e(em apples, oranges, and bananas. +This is not that \e(em rather, this is that. +.Ed +.Pp +Note: +hyphens, minus signs, and en-dashes look identical under normal ASCII output. +Other formats, such as PostScript, render them correctly, +with differing widths. +.Ss Spaces +To separate words in normal text, for indenting and alignment +in literal context, and when none of the following special cases apply, +just use the normal space character +.Pq Sq \ . +.Pp +When filling text, lines may be broken between words, i.e. at space +characters. +To prevent a line break between two particular words, +use the non-breaking space escape sequence +.Pq Sq \e~ +instead of the normal space character. +For example, the input string +.Dq number\e~1 +will be kept together as +.Dq number\~1 +on the same output line. +.Pp +On request and macro lines, the normal space character serves as an +argument delimiter. +To include whitespace into arguments, quoting is usually the best choice. +In some cases, using either the non-breaking +.Pq Sq \e~ +or the breaking +.Pq Sq \e\ \& +space escape sequence may be preferable. +To escape macro names and to protect whitespace at the end +of input lines, the zero-width space +.Pq Sq \e& +is often useful. +For example, in +.Xr mdoc 7 , +a normal space character can be displayed in single quotes in either +of the following ways: +.Pp +.Dl .Sq \(dq \(dq +.Dl .Sq \e \e& +.Ss Quotes +On request and macro lines, the double-quote character +.Pq Sq \(dq +is handled specially to allow quoting. +One way to prevent this special handling is by using the +.Sq \e(dq +escape sequence. +.Pp +Note that on text lines, literal double-quote characters can be used +verbatim. +All other quote-like characters can be used verbatim as well, +even on request and macro lines. +.Ss Periods +The period +.Pq Sq \&. +is handled specially at the beginning of an input line, +where it introduces a +.Xr roff 7 +request or a macro, and when appearing alone as a macro argument in +.Xr mdoc 7 . +In such situations, prepend a zero-width space +.Pq Sq \e&. +to make it behave like normal text. +.Pp +Do not use the +.Sq \e. +escape sequence. +It does not prevent special handling of the period. +.Ss Backslashes +To include a literal backslash +.Pq Sq \e +into the output, use the +.Pq Sq \ee +escape sequence. +.Pp +Note that doubling it +.Pq Sq \e\e +is not the right way to output a backslash. +Because +.Xr mandoc 1 +does not implement full +.Xr roff 7 +functionality, it may work with +.Xr mandoc 1 , +but it may have weird effects on complete +.Xr roff 7 +implementations. +.Sh SPECIAL CHARACTERS +Special characters are encoded as .Sq \eX .Pq for a one-character escape , .Sq \e(XX @@ -41,40 +185,14 @@ encode special characters with and .Sq \e[N] .Pq N-character . -One may generalise -.Sq \e(XX -as -.Sq \e[XX] -and -.Sq \eX -as -.Sq \e[X] . -Predefined strings are functionally similar to special characters, using -.Sq \e*X -.Pq for a one-character escape , -.Sq \e*(XX -.Pq two-character , -and -.Sq \e*[N] -.Pq N-character . -One may generalise -.Sq \e*(XX -as -.Sq \e*[XX] -and -.Sq \e*X -as -.Sq \e*[X] . -.Pp -Note that each output mode will have a different rendering of the -characters. -It's guaranteed that each input symbol will correspond to a -(more or less) meaningful output rendering, regardless the mode. -.Sh SPECIAL CHARACTERS -These are the preferred input symbols for producing special characters. +For details, see the +.Em Special Characters +subsection of the +.Xr roff 7 +manual. .Pp Spacing: -.Bl -column -compact -offset indent "Input" "Description" +.Bl -column "Input" "Description" -offset indent -compact .It Em Input Ta Em Description .It \e~ Ta non-breaking, non-collapsing space .It \e Ta breaking, non-collapsing n-width space @@ -87,7 +205,7 @@ Spacing: .El .Pp Lines: -.Bl -column -compact -offset indent "Input" "Rendered" "Description" +.Bl -column "Input" "Rendered" "Description" -offset indent -compact .It Em Input Ta Em Rendered Ta Em Description .It \e(ba Ta \(ba Ta bar .It \e(br Ta \(br Ta box rule @@ -99,7 +217,7 @@ Lines: .El .Pp Text markers: -.Bl -column -compact -offset indent "Input" "Rendered" "Description" +.Bl -column "Input" "Rendered" "Description" -offset indent -compact .It Em Input Ta Em Rendered Ta Em Description .It \e(ci Ta \(ci Ta circle .It \e(bu Ta \(bu Ta bullet @@ -118,7 +236,7 @@ Text markers: .El .Pp Legal symbols: -.Bl -column -compact -offset indent "Input" "Rendered" "Description" +.Bl -column "Input" "Rendered" "Description" -offset indent -compact .It Em Input Ta Em Rendered Ta Em Description .It \e(co Ta \(co Ta copyright .It \e(rg Ta \(rg Ta registered @@ -126,7 +244,7 @@ Legal symbols: .El .Pp Punctuation: -.Bl -column -compact -offset indent "Input" "Rendered" "Description" +.Bl -column "Input" "Rendered" "Description" -offset indent -compact .It Em Input Ta Em Rendered Ta Em Description .It \e(em Ta \(em Ta em-dash .It \e(en Ta \(en Ta en-dash @@ -138,7 +256,7 @@ Punctuation: .El .Pp Quotes: -.Bl -column -compact -offset indent "Input" "Rendered" "Description" +.Bl -column "Input" "Rendered" "Description" -offset indent -compact .It Em Input Ta Em Rendered Ta Em Description .It \e(Bq Ta \(Bq Ta right low double-quote .It \e(bq Ta \(bq Ta right low single-quote @@ -155,7 +273,7 @@ Quotes: .El .Pp Brackets: -.Bl -column -compact -offset indent "xxbracketrightbpx" Rendered Description +.Bl -column "xxbracketrightbpx" Rendered Description -offset indent -compact .It Em Input Ta Em Rendered Ta Em Description .It \e(lB Ta \(lB Ta left bracket .It \e(rB Ta \(rB Ta right bracket @@ -194,7 +312,7 @@ Brackets: .El .Pp Arrows: -.Bl -column -compact -offset indent "Input" "Rendered" "Description" +.Bl -column "Input" "Rendered" "Description" -offset indent -compact .It Em Input Ta Em Rendered Ta Em Description .It \e(<- Ta \(<- Ta left arrow .It \e(-> Ta \(-> Ta right arrow @@ -211,7 +329,7 @@ Arrows: .El .Pp Logical: -.Bl -column -compact -offset indent "Input" "Rendered" "Description" +.Bl -column "Input" "Rendered" "Description" -offset indent -compact .It Em Input Ta Em Rendered Ta Em Description .It \e(AN Ta \(AN Ta logical and .It \e(OR Ta \(OR Ta logical or @@ -226,7 +344,7 @@ Logical: .El .Pp Mathematical: -.Bl -column -compact -offset indent "xxcoproductxx" "Rendered" "Description" +.Bl -column "xxcoproductxx" "Rendered" "Description" -offset indent -compact .It Em Input Ta Em Rendered Ta Em Description .It \e(pl Ta \(pl Ta plus .It \e(mi Ta \(mi Ta minus @@ -288,10 +406,13 @@ Mathematical: .It \e(Re Ta \(Re Ta real .It \e(pd Ta \(pd Ta partial differential .It \e(-h Ta \(-h Ta Planck constant over 2\(*p +.It \e[12] Ta \[12] Ta one-half +.It \e[14] Ta \[14] Ta one-fourth +.It \e[34] Ta \[34] Ta three-fourths .El .Pp Ligatures: -.Bl -column -compact -offset indent "Input" "Rendered" "Description" +.Bl -column "Input" "Rendered" "Description" -offset indent -compact .It Em Input Ta Em Rendered Ta Em Description .It \e(ff Ta \(ff Ta ff ligature .It \e(fi Ta \(fi Ta fi ligature @@ -308,7 +429,7 @@ Ligatures: .El .Pp Accents: -.Bl -column -compact -offset indent "Input" "Rendered" "Description" +.Bl -column "Input" "Rendered" "Description" -offset indent -compact .It Em Input Ta Em Rendered Ta Em Description .It \e(a" Ta \(a" Ta Hungarian umlaut .It \e(a- Ta \(a- Ta macron @@ -330,7 +451,7 @@ Accents: .El .Pp Accented letters: -.Bl -column -compact -offset indent "Input" "Rendered" "Description" +.Bl -column "Input" "Rendered" "Description" -offset indent -compact .It Em Input Ta Em Rendered Ta Em Description .It \e('A Ta \('A Ta acute A .It \e('E Ta \('E Ta acute E @@ -390,7 +511,7 @@ Accented letters: .El .Pp Special letters: -.Bl -column -compact -offset indent "Input" "Rendered" "Description" +.Bl -column "Input" "Rendered" "Description" -offset indent -compact .It Em Input Ta Em Rendered Ta Em Description .It \e(-D Ta \(-D Ta Eth .It \e(Sd Ta \(Sd Ta eth @@ -401,7 +522,7 @@ Special letters: .El .Pp Currency: -.Bl -column -compact -offset indent "Input" "Rendered" "Description" +.Bl -column "Input" "Rendered" "Description" -offset indent -compact .It Em Input Ta Em Rendered Ta Em Description .It \e(Do Ta \(Do Ta dollar .It \e(ct Ta \(ct Ta cent @@ -414,7 +535,7 @@ Currency: .El .Pp Units: -.Bl -column -compact -offset indent "Input" "Rendered" "Description" +.Bl -column "Input" "Rendered" "Description" -offset indent -compact .It Em Input Ta Em Rendered Ta Em Description .It \e(de Ta \(de Ta degree .It \e(%0 Ta \(%0 Ta per-thousand @@ -424,7 +545,7 @@ Units: .El .Pp Greek letters: -.Bl -column -compact -offset indent "Input" "Rendered" "Description" +.Bl -column "Input" "Rendered" "Description" -offset indent -compact .It Em Input Ta Em Rendered Ta Em Description .It \e(*A Ta \(*A Ta Alpha .It \e(*B Ta \(*B Ta Beta @@ -481,10 +602,28 @@ Greek letters: .It \e(ts Ta \(ts Ta sigma terminal .El .Sh PREDEFINED STRINGS -These are not recommended for use, as they differ across -implementations: +Predefined strings are inherited from the macro packages of historical +troff implementations. +They are +.Em not recommended +for use, as they differ across implementations. +Manuals using these predefined strings are almost certainly not +portable. .Pp -.Bl -column -compact -offset indent "Input" "Rendered" "Description" +Their syntax is similar to special characters, using +.Sq \e*X +.Pq for a one-character escape , +.Sq \e*(XX +.Pq two-character , +and +.Sq \e*[N] +.Pq N-character . +For details, see the +.Em Predefined Strings +subsection of the +.Xr roff 7 +manual. +.Bl -column "Input" "Rendered" "Description" -offset indent .It Em Input Ta Em Rendered Ta Em Description .It \e*(Ba Ta \*(Ba Ta vertical bar .It \e*(Ne Ta \*(Ne Ta not equal @@ -512,39 +651,85 @@ implementations: .It \e*(>= Ta \*(>= Ta greater-than-equal .It \e*(aa Ta \*(aa Ta acute .It \e*(ga Ta \*(ga Ta grave +.It \e*(Px Ta \*(Px Ta POSIX standard name +.It \e*(Ai Ta \*(Ai Ta ANSI standard name .El -.Sh COMPATIBILITY -This section documents compatibility of -.Nm -with older or existing versions of groff. +.Sh UNICODE CHARACTERS +The escape sequence .Pp -The following render differently in -.Fl T Ns Ar ascii -output mode: -.Bd -ragged -offset indent -\e(ss, \e(nm, \e(nb, \e(nc, \e(ib, \e(ip, \e(pp, \e[sum], \e[product], -\e[coproduct], \e(gr, \e(-h, \e(a. -.Ed +.Dl \e[uXXXX] .Pp -The following render differently in -.Fl T Ns Ar html -output mode: -.Bd -ragged -offset indent -\e(~=, \e(nb, \e(nc -.Ed -.Pp -Finally, the following have been omitted by being poorly documented or -having no known representation: -.Bd -ragged -offset indent -\e[radicalex], \e[sqrtex], \e(ru -.Ed -.Sh SEE ALSO +is interpreted as a Unicode codepoint. +The codepoint must be in the range above U+0080 and less than U+10FFFF. +For compatibility, points must be zero-padded to four characters; if +greater than four characters, no zero padding is allowed. +Unicode surrogates are not allowed. +.\" .Pp +.\" Unicode glyphs attenuate to the +.\" .Sq \&? +.\" character if invalid or not rendered by current output media. +.Sh NUMBERED CHARACTERS +For backward compatibility with existing manuals, .Xr mandoc 1 +also supports the +.Pp +.Dl \eN\(aq Ns Ar number Ns \(aq +.Pp +escape sequence, inserting the character +.Ar number +from the current character set into the output. +Of course, this is inherently non-portable and is already marked +as deprecated in the Heirloom roff manual. +For example, do not use \eN'34', use \e(dq, or even the plain +.Sq \(dq +character where possible. +.Sh COMPATIBILITY +This section documents compatibility between mandoc and other other +troff implementations, at this time limited to GNU troff +.Pq Qq groff . +.Pp +.Bl -dash -compact +.It +The \eN\(aq\(aq escape sequence is limited to printable characters; in +groff, it accepts arbitrary character numbers. +.It +In +.Fl T Ns Cm ascii , +the +\e(ss, \e(nm, \e(nb, \e(nc, \e(ib, \e(ip, \e(pp, \e[sum], \e[product], +\e[coproduct], \e(gr, \e(\-h, and \e(a. special characters render +differently between mandoc and groff. +.It +In +.Fl T Ns Cm html +and +.Fl T Ns Cm xhtml , +the \e(~=, \e(nb, and \e(nc special characters render differently +between mandoc and groff. +.It +The +.Fl T Ns Cm ps +and +.Fl T Ns Cm pdf +modes format like +.Fl T Ns Cm ascii +instead of rendering glyphs as in groff. +.It +The \e[radicalex], \e[sqrtex], and \e(ru special characters have been omitted +from mandoc either because they are poorly documented or they have no +known representation. +.El +.Sh SEE ALSO +.Xr mandoc 1 , +.Xr man 7 , +.Xr mdoc 7 , +.Xr roff 7 .Sh AUTHORS The .Nm manual page was written by -.An Kristaps Dzonsons Aq kristaps@bsd.lv . +.An Kristaps Dzonsons , +.Mt kristaps@bsd.lv . .Sh CAVEATS The .Sq \e*(Ba diff --git a/external/bsd/mdocml/dist/mandocdb.8 b/external/bsd/mdocml/dist/mandocdb.8 new file mode 100644 index 000000000..d864e0ea1 --- /dev/null +++ b/external/bsd/mdocml/dist/mandocdb.8 @@ -0,0 +1,293 @@ +.\" $Vendor-Id: mandocdb.8,v 1.17 2011/12/25 21:00:23 schwarze Exp $ +.\" +.\" Copyright (c) 2011 Kristaps Dzonsons +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd December 25, 2011 +.Dt MANDOCDB 8 +.Os +.Sh NAME +.Nm mandocdb +.Nd index UNIX manuals +.Sh SYNOPSIS +.Nm +.Op Fl avW +.Op Fl C Ar file +.Nm +.Op Fl avW +.Ar dir ... +.Nm +.Op Fl vW +.Fl d Ar dir +.Op Ar +.Nm +.Op Fl vW +.Fl u Ar dir +.Op Ar +.Nm +.Fl t Ar +.Sh DESCRIPTION +The +.Nm +utility extracts keywords from +.Ux +manuals and indexes them in a +.Sx Keyword Database +and +.Sx Index Database +for fast retrieval by +.Xr apropos 1 , +.Xr whatis 1 , +and +.Xr man 1 Ns 's +.Fl k +option. +.Pp +By default, +.Nm +creates databases in each +.Ar dir +using the files +.Sm off +.Sy man Ar section Li / +.Op Ar arch Li / +.Ar title . section +.Sm on +and +.Sm off +.Sy cat Ar section Li / +.Op Ar arch Li / +.Ar title . Sy 0 +.Sm on +in that directory; +existing databases are truncated. +If +.Ar dir +is not provided, +.Nm +uses the default paths stipulated by +.Xr man 1 . +.Pp +The arguments are as follows: +.Bl -tag -width "-C file" +.It Fl a +Use all directories and files found below +.Ar dir ... . +.It Fl C Ar file +Specify an alternative configuration +.Ar file +in +.Xr man.conf 5 +format. +.It Fl d Ar dir +Merge (remove and re-add) +.Ar +to the database in +.Ar dir +without truncating it. +.It Fl t Ar +Check the given +.Ar files +for potential problems. +No databases are modified. +Implies +.Fl a +and +.Fl W . +All diagnostic messages are printed to the standard output; +the standard error output is not used. +.It Fl u Ar dir +Remove +.Ar +from the database in +.Ar dir +without truncating it. +.It Fl v +Display all files added or removed to the index. +.It Fl W +Print warnings about potential problems with manual pages +to the standard error output. +.El +.Pp +If fatal parse errors are encountered while parsing, the offending file +is printed to stderr, omitted from the index, and the parse continues +with the next input file. +.Ss Index Database +The index database, +.Pa whatis.index , +is a +.Xr recno 3 +database with record values consisting of +.Pp +.Bl -enum -compact +.It +the character +.Cm d , +.Cm a , +or +.Cm c +to indicate the file type +.Po +.Xr mdoc 7 , +.Xr man 7 , +and post-formatted, respectively +.Pc , +.It +the filename relative to the databases' path, +.It +the manual section, +.It +the manual title, +.It +the architecture +.Pq often empty , +.It +and the description. +.El +.Pp +Each of the above is NUL-terminated. +.Pp +If the record value is zero-length, it is unassigned. +.Ss Keyword Database +The keyword database, +.Pa whatis.db , +is a +.Xr btree 3 +database of NUL-terminated keywords (record length is non-zero string +length plus one) mapping to a 16-byte binary field consisting of the +64-bit keyword type and the 64-bit +.Sx Index Database +record number, both in network-byte order. +.Pp +The type bit-mask consists of the following +values mapping into +.Xr mdoc 7 +macro identifiers: +.Pp +.Bl -column "x0x0000000000000001ULLx" "xLix" -offset indent -compact +.It Li 0x0000000000000001ULL Ta \&An +.It Li 0x0000000000000002ULL Ta \&Ar +.It Li 0x0000000000000004ULL Ta \&At +.It Li 0x0000000000000008ULL Ta \&Bsx +.It Li 0x0000000000000010ULL Ta \&Bx +.It Li 0x0000000000000020ULL Ta \&Cd +.It Li 0x0000000000000040ULL Ta \&Cm +.It Li 0x0000000000000080ULL Ta \&Dv +.It Li 0x0000000000000100ULL Ta \&Dx +.It Li 0x0000000000000200ULL Ta \&Em +.It Li 0x0000000000000400ULL Ta \&Er +.It Li 0x0000000000000800ULL Ta \&Ev +.It Li 0x0000000000001000ULL Ta \&Fa +.It Li 0x0000000000002000ULL Ta \&Fl +.It Li 0x0000000000004000ULL Ta \&Fn +.It Li 0x0000000000008000ULL Ta \&Ft +.It Li 0x0000000000010000ULL Ta \&Fx +.It Li 0x0000000000020000ULL Ta \&Ic +.It Li 0x0000000000040000ULL Ta \&In +.It Li 0x0000000000080000ULL Ta \&Lb +.It Li 0x0000000000100000ULL Ta \&Li +.It Li 0x0000000000200000ULL Ta \&Lk +.It Li 0x0000000000400000ULL Ta \&Ms +.It Li 0x0000000000800000ULL Ta \&Mt +.It Li 0x0000000001000000ULL Ta \&Nd +.It Li 0x0000000002000000ULL Ta \&Nm +.It Li 0x0000000004000000ULL Ta \&Nx +.It Li 0x0000000008000000ULL Ta \&Ox +.It Li 0x0000000010000000ULL Ta \&Pa +.It Li 0x0000000020000000ULL Ta \&Rs +.It Li 0x0000000040000000ULL Ta \&Sh +.It Li 0x0000000080000000ULL Ta \&Ss +.It Li 0x0000000100000000ULL Ta \&St +.It Li 0x0000000200000000ULL Ta \&Sy +.It Li 0x0000000400000000ULL Ta \&Tn +.It Li 0x0000000800000000ULL Ta \&Va +.It Li 0x0000001000000000ULL Ta \&Vt +.It Li 0x0000002000000000ULL Ta \&Xr +.El +.Sh IMPLEMENTATION NOTES +The time to construct a new database pair grows linearly with the +number of keywords in the input files. +However, removing or updating entries with +.Fl u +or +.Fl d , +respectively, grows as a multiple of the index length and input size. +.Sh FILES +.Bl -tag -width Ds +.It Pa whatis.db +A +.Xr btree 3 +keyword database mapping keywords to a type and file reference in +.Pa whatis.index . +.It Pa whatis.index +A +.Xr recno 3 +database of indexed file-names. +.It Pa /etc/man.conf +The default +.Xr man 1 +configuration file. +.El +.Sh EXIT STATUS +The +.Nm +utility exits with one of the following values: +.Pp +.Bl -tag -width Ds -compact +.It 0 +No errors occurred. +.It 5 +Invalid command line arguments were specified. +No input files have been read. +.It 6 +An operating system error occurred, for example memory exhaustion or an +error accessing input files. +Such errors cause +.Nm +to exit at once, possibly in the middle of parsing or formatting a file. +The output databases are corrupt and should be removed. +.El +.Sh DIAGNOSTICS +If the following errors occur, the +.Nm +databases should be rebuilt. +.Bl -diag +.It "%s: Corrupt database" +The keyword database file indicated by +.Pa %s +is unreadable. +.It "%s: Corrupt index" +The index database file indicated by +.Pa %s +is unreadable. +.It "%s: Path too long" +The file +.Pa %s +is too long. +This usually indicates database corruption or invalid command-line +arguments. +.El +.Sh SEE ALSO +.Xr apropos 1 , +.Xr man 1 , +.Xr whatis 1 , +.Xr btree 3 , +.Xr recno 3 , +.Xr man.conf 5 +.Sh AUTHORS +The +.Nm +utility was written by +.An Kristaps Dzonsons , +.Mt kristaps@bsd.lv . diff --git a/external/bsd/mdocml/dist/mandocdb.c b/external/bsd/mdocml/dist/mandocdb.c new file mode 100644 index 000000000..d65831117 --- /dev/null +++ b/external/bsd/mdocml/dist/mandocdb.c @@ -0,0 +1,1834 @@ +/* $Vendor-Id: mandocdb.c,v 1.43 2011/12/31 18:47:52 kristaps Exp $ */ +/* + * Copyright (c) 2011 Kristaps Dzonsons + * Copyright (c) 2011 Ingo Schwarze + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(__linux__) +# include +# include +#elif defined(__APPLE__) +# include +# include +#else +# include +#endif + +#include "man.h" +#include "mdoc.h" +#include "mandoc.h" +#include "mandocdb.h" +#include "manpath.h" + +#define MANDOC_BUFSZ BUFSIZ +#define MANDOC_SLOP 1024 + +#define MANDOC_SRC 0x1 +#define MANDOC_FORM 0x2 + +/* Access to the mandoc database on disk. */ + +struct mdb { + char idxn[MAXPATHLEN]; /* index db filename */ + char dbn[MAXPATHLEN]; /* keyword db filename */ + DB *idx; /* index recno database */ + DB *db; /* keyword btree database */ +}; + +/* Stack of temporarily unused index records. */ + +struct recs { + recno_t *stack; /* pointer to a malloc'ed array */ + size_t size; /* number of allocated slots */ + size_t cur; /* current number of empty records */ + recno_t last; /* last record number in the index */ +}; + +/* Tiny list for files. No need to bring in QUEUE. */ + +struct of { + char *fname; /* heap-allocated */ + char *sec; + char *arch; + char *title; + int src_form; + struct of *next; /* NULL for last one */ + struct of *first; /* first in list */ +}; + +/* Buffer for storing growable data. */ + +struct buf { + char *cp; + size_t len; /* current length */ + size_t size; /* total buffer size */ +}; + +/* Operation we're going to perform. */ + +enum op { + OP_DEFAULT = 0, /* new dbs from dir list or default config */ + OP_CONFFILE, /* new databases from custom config file */ + OP_UPDATE, /* delete/add entries in existing database */ + OP_DELETE, /* delete entries from existing database */ + OP_TEST /* change no databases, report potential problems */ +}; + +#define MAN_ARGS DB *hash, \ + struct buf *buf, \ + struct buf *dbuf, \ + const struct man_node *n +#define MDOC_ARGS DB *hash, \ + struct buf *buf, \ + struct buf *dbuf, \ + const struct mdoc_node *n, \ + const struct mdoc_meta *m + +static void buf_appendmdoc(struct buf *, + const struct mdoc_node *, int); +static void buf_append(struct buf *, const char *); +static void buf_appendb(struct buf *, + const void *, size_t); +static void dbt_put(DB *, const char *, DBT *, DBT *); +static void hash_put(DB *, const struct buf *, uint64_t); +static void hash_reset(DB **); +static void index_merge(const struct of *, struct mparse *, + struct buf *, struct buf *, DB *, + struct mdb *, struct recs *); +static void index_prune(const struct of *, struct mdb *, + struct recs *); +static void ofile_argbuild(int, char *[], struct of **); +static void ofile_dirbuild(const char *, const char *, + const char *, int, struct of **); +static void ofile_free(struct of *); +static void pformatted(DB *, struct buf *, + struct buf *, const struct of *); +static int pman_node(MAN_ARGS); +static void pmdoc_node(MDOC_ARGS); +static int pmdoc_head(MDOC_ARGS); +static int pmdoc_body(MDOC_ARGS); +static int pmdoc_Fd(MDOC_ARGS); +static int pmdoc_In(MDOC_ARGS); +static int pmdoc_Fn(MDOC_ARGS); +static int pmdoc_Nd(MDOC_ARGS); +static int pmdoc_Nm(MDOC_ARGS); +static int pmdoc_Sh(MDOC_ARGS); +static int pmdoc_St(MDOC_ARGS); +static int pmdoc_Xr(MDOC_ARGS); + +#define MDOCF_CHILD 0x01 /* Automatically index child nodes. */ + +struct mdoc_handler { + int (*fp)(MDOC_ARGS); /* Optional handler. */ + uint64_t mask; /* Set unless handler returns 0. */ + int flags; /* For use by pmdoc_node. */ +}; + +static const struct mdoc_handler mdocs[MDOC_MAX] = { + { NULL, 0, 0 }, /* Ap */ + { NULL, 0, 0 }, /* Dd */ + { NULL, 0, 0 }, /* Dt */ + { NULL, 0, 0 }, /* Os */ + { pmdoc_Sh, TYPE_Sh, MDOCF_CHILD }, /* Sh */ + { pmdoc_head, TYPE_Ss, MDOCF_CHILD }, /* Ss */ + { NULL, 0, 0 }, /* Pp */ + { NULL, 0, 0 }, /* D1 */ + { NULL, 0, 0 }, /* Dl */ + { NULL, 0, 0 }, /* Bd */ + { NULL, 0, 0 }, /* Ed */ + { NULL, 0, 0 }, /* Bl */ + { NULL, 0, 0 }, /* El */ + { NULL, 0, 0 }, /* It */ + { NULL, 0, 0 }, /* Ad */ + { NULL, TYPE_An, MDOCF_CHILD }, /* An */ + { NULL, TYPE_Ar, MDOCF_CHILD }, /* Ar */ + { NULL, TYPE_Cd, MDOCF_CHILD }, /* Cd */ + { NULL, TYPE_Cm, MDOCF_CHILD }, /* Cm */ + { NULL, TYPE_Dv, MDOCF_CHILD }, /* Dv */ + { NULL, TYPE_Er, MDOCF_CHILD }, /* Er */ + { NULL, TYPE_Ev, MDOCF_CHILD }, /* Ev */ + { NULL, 0, 0 }, /* Ex */ + { NULL, TYPE_Fa, MDOCF_CHILD }, /* Fa */ + { pmdoc_Fd, TYPE_In, 0 }, /* Fd */ + { NULL, TYPE_Fl, MDOCF_CHILD }, /* Fl */ + { pmdoc_Fn, 0, 0 }, /* Fn */ + { NULL, TYPE_Ft, MDOCF_CHILD }, /* Ft */ + { NULL, TYPE_Ic, MDOCF_CHILD }, /* Ic */ + { pmdoc_In, TYPE_In, 0 }, /* In */ + { NULL, TYPE_Li, MDOCF_CHILD }, /* Li */ + { pmdoc_Nd, TYPE_Nd, MDOCF_CHILD }, /* Nd */ + { pmdoc_Nm, TYPE_Nm, MDOCF_CHILD }, /* Nm */ + { NULL, 0, 0 }, /* Op */ + { NULL, 0, 0 }, /* Ot */ + { NULL, TYPE_Pa, MDOCF_CHILD }, /* Pa */ + { NULL, 0, 0 }, /* Rv */ + { pmdoc_St, TYPE_St, 0 }, /* St */ + { NULL, TYPE_Va, MDOCF_CHILD }, /* Va */ + { pmdoc_body, TYPE_Va, MDOCF_CHILD }, /* Vt */ + { pmdoc_Xr, TYPE_Xr, 0 }, /* Xr */ + { NULL, 0, 0 }, /* %A */ + { NULL, 0, 0 }, /* %B */ + { NULL, 0, 0 }, /* %D */ + { NULL, 0, 0 }, /* %I */ + { NULL, 0, 0 }, /* %J */ + { NULL, 0, 0 }, /* %N */ + { NULL, 0, 0 }, /* %O */ + { NULL, 0, 0 }, /* %P */ + { NULL, 0, 0 }, /* %R */ + { NULL, 0, 0 }, /* %T */ + { NULL, 0, 0 }, /* %V */ + { NULL, 0, 0 }, /* Ac */ + { NULL, 0, 0 }, /* Ao */ + { NULL, 0, 0 }, /* Aq */ + { NULL, TYPE_At, MDOCF_CHILD }, /* At */ + { NULL, 0, 0 }, /* Bc */ + { NULL, 0, 0 }, /* Bf */ + { NULL, 0, 0 }, /* Bo */ + { NULL, 0, 0 }, /* Bq */ + { NULL, TYPE_Bsx, MDOCF_CHILD }, /* Bsx */ + { NULL, TYPE_Bx, MDOCF_CHILD }, /* Bx */ + { NULL, 0, 0 }, /* Db */ + { NULL, 0, 0 }, /* Dc */ + { NULL, 0, 0 }, /* Do */ + { NULL, 0, 0 }, /* Dq */ + { NULL, 0, 0 }, /* Ec */ + { NULL, 0, 0 }, /* Ef */ + { NULL, TYPE_Em, MDOCF_CHILD }, /* Em */ + { NULL, 0, 0 }, /* Eo */ + { NULL, TYPE_Fx, MDOCF_CHILD }, /* Fx */ + { NULL, TYPE_Ms, MDOCF_CHILD }, /* Ms */ + { NULL, 0, 0 }, /* No */ + { NULL, 0, 0 }, /* Ns */ + { NULL, TYPE_Nx, MDOCF_CHILD }, /* Nx */ + { NULL, TYPE_Ox, MDOCF_CHILD }, /* Ox */ + { NULL, 0, 0 }, /* Pc */ + { NULL, 0, 0 }, /* Pf */ + { NULL, 0, 0 }, /* Po */ + { NULL, 0, 0 }, /* Pq */ + { NULL, 0, 0 }, /* Qc */ + { NULL, 0, 0 }, /* Ql */ + { NULL, 0, 0 }, /* Qo */ + { NULL, 0, 0 }, /* Qq */ + { NULL, 0, 0 }, /* Re */ + { NULL, 0, 0 }, /* Rs */ + { NULL, 0, 0 }, /* Sc */ + { NULL, 0, 0 }, /* So */ + { NULL, 0, 0 }, /* Sq */ + { NULL, 0, 0 }, /* Sm */ + { NULL, 0, 0 }, /* Sx */ + { NULL, TYPE_Sy, MDOCF_CHILD }, /* Sy */ + { NULL, TYPE_Tn, MDOCF_CHILD }, /* Tn */ + { NULL, 0, 0 }, /* Ux */ + { NULL, 0, 0 }, /* Xc */ + { NULL, 0, 0 }, /* Xo */ + { pmdoc_head, TYPE_Fn, 0 }, /* Fo */ + { NULL, 0, 0 }, /* Fc */ + { NULL, 0, 0 }, /* Oo */ + { NULL, 0, 0 }, /* Oc */ + { NULL, 0, 0 }, /* Bk */ + { NULL, 0, 0 }, /* Ek */ + { NULL, 0, 0 }, /* Bt */ + { NULL, 0, 0 }, /* Hf */ + { NULL, 0, 0 }, /* Fr */ + { NULL, 0, 0 }, /* Ud */ + { NULL, TYPE_Lb, MDOCF_CHILD }, /* Lb */ + { NULL, 0, 0 }, /* Lp */ + { NULL, TYPE_Lk, MDOCF_CHILD }, /* Lk */ + { NULL, TYPE_Mt, MDOCF_CHILD }, /* Mt */ + { NULL, 0, 0 }, /* Brq */ + { NULL, 0, 0 }, /* Bro */ + { NULL, 0, 0 }, /* Brc */ + { NULL, 0, 0 }, /* %C */ + { NULL, 0, 0 }, /* Es */ + { NULL, 0, 0 }, /* En */ + { NULL, TYPE_Dx, MDOCF_CHILD }, /* Dx */ + { NULL, 0, 0 }, /* %Q */ + { NULL, 0, 0 }, /* br */ + { NULL, 0, 0 }, /* sp */ + { NULL, 0, 0 }, /* %U */ + { NULL, 0, 0 }, /* Ta */ +}; + +static const char *progname; +static int use_all; /* Use all directories and files. */ +static int verb; /* Output verbosity level. */ +static int warnings; /* Potential problems in manuals. */ + +int +main(int argc, char *argv[]) +{ + struct mparse *mp; /* parse sequence */ + struct manpaths dirs; + struct mdb mdb; + struct recs recs; + enum op op; /* current operation */ + const char *dir; + char *cp; + char pbuf[PATH_MAX]; + int ch, i, flags; + DB *hash; /* temporary keyword hashtable */ + BTREEINFO info; /* btree configuration */ + size_t sz1, sz2; + struct buf buf, /* keyword buffer */ + dbuf; /* description buffer */ + struct of *of; /* list of files for processing */ + extern int optind; + extern char *optarg; + + progname = strrchr(argv[0], '/'); + if (progname == NULL) + progname = argv[0]; + else + ++progname; + + memset(&dirs, 0, sizeof(struct manpaths)); + memset(&mdb, 0, sizeof(struct mdb)); + memset(&recs, 0, sizeof(struct recs)); + + of = NULL; + mp = NULL; + hash = NULL; + op = OP_DEFAULT; + dir = NULL; + + while (-1 != (ch = getopt(argc, argv, "aC:d:tu:vW"))) + switch (ch) { + case ('a'): + use_all = 1; + break; + case ('C'): + if (op) { + fprintf(stderr, + "-C: conflicting options\n"); + goto usage; + } + dir = optarg; + op = OP_CONFFILE; + break; + case ('d'): + if (op) { + fprintf(stderr, + "-d: conflicting options\n"); + goto usage; + } + dir = optarg; + op = OP_UPDATE; + break; + case ('t'): + dup2(STDOUT_FILENO, STDERR_FILENO); + if (op) { + fprintf(stderr, + "-t: conflicting options\n"); + goto usage; + } + op = OP_TEST; + use_all = 1; + warnings = 1; + break; + case ('u'): + if (op) { + fprintf(stderr, + "-u: conflicting options\n"); + goto usage; + } + dir = optarg; + op = OP_DELETE; + break; + case ('v'): + verb++; + break; + case ('W'): + warnings = 1; + break; + default: + goto usage; + } + + argc -= optind; + argv += optind; + + if (OP_CONFFILE == op && argc > 0) { + fprintf(stderr, "-C: too many arguments\n"); + goto usage; + } + + memset(&info, 0, sizeof(BTREEINFO)); + info.flags = R_DUP; + + mp = mparse_alloc(MPARSE_AUTO, MANDOCLEVEL_FATAL, NULL, NULL); + + memset(&buf, 0, sizeof(struct buf)); + memset(&dbuf, 0, sizeof(struct buf)); + + buf.size = dbuf.size = MANDOC_BUFSZ; + + buf.cp = mandoc_malloc(buf.size); + dbuf.cp = mandoc_malloc(dbuf.size); + + flags = O_CREAT | O_RDWR; + if (OP_DEFAULT == op || OP_CONFFILE == op) + flags |= O_TRUNC; + + if (OP_TEST == op) { + ofile_argbuild(argc, argv, &of); + if (NULL == of) + goto out; + index_merge(of, mp, &dbuf, &buf, hash, &mdb, &recs); + goto out; + } + + if (OP_UPDATE == op || OP_DELETE == op) { + strlcat(mdb.dbn, dir, MAXPATHLEN); + strlcat(mdb.dbn, "/", MAXPATHLEN); + sz1 = strlcat(mdb.dbn, MANDOC_DB, MAXPATHLEN); + + strlcat(mdb.idxn, dir, MAXPATHLEN); + strlcat(mdb.idxn, "/", MAXPATHLEN); + sz2 = strlcat(mdb.idxn, MANDOC_IDX, MAXPATHLEN); + + if (sz1 >= MAXPATHLEN || sz2 >= MAXPATHLEN) { + fprintf(stderr, "%s: path too long\n", dir); + exit((int)MANDOCLEVEL_BADARG); + } + + mdb.db = dbopen(mdb.dbn, flags, 0644, DB_BTREE, &info); + mdb.idx = dbopen(mdb.idxn, flags, 0644, DB_RECNO, NULL); + + if (NULL == mdb.db) { + perror(mdb.dbn); + exit((int)MANDOCLEVEL_SYSERR); + } else if (NULL == mdb.idx) { + perror(mdb.idxn); + exit((int)MANDOCLEVEL_SYSERR); + } + + ofile_argbuild(argc, argv, &of); + + if (NULL == of) + goto out; + + index_prune(of, &mdb, &recs); + + /* + * Go to the root of the respective manual tree. + * This must work or no manuals may be found (they're + * indexed relative to the root). + */ + + if (OP_UPDATE == op) { + if (-1 == chdir(dir)) { + perror(dir); + exit((int)MANDOCLEVEL_SYSERR); + } + index_merge(of, mp, &dbuf, &buf, hash, + &mdb, &recs); + } + + goto out; + } + + /* + * Configure the directories we're going to scan. + * If we have command-line arguments, use them. + * If not, we use man(1)'s method (see mandocdb.8). + */ + + if (argc > 0) { + dirs.paths = mandoc_calloc(argc, sizeof(char *)); + dirs.sz = argc; + for (i = 0; i < argc; i++) { + if (NULL == (cp = realpath(argv[i], pbuf))) { + perror(argv[i]); + goto out; + } + dirs.paths[i] = mandoc_strdup(cp); + } + } else + manpath_parse(&dirs, dir, NULL, NULL); + + for (i = 0; i < dirs.sz; i++) { + mdb.idxn[0] = mdb.dbn[0] = '\0'; + + strlcat(mdb.dbn, dirs.paths[i], MAXPATHLEN); + strlcat(mdb.dbn, "/", MAXPATHLEN); + sz1 = strlcat(mdb.dbn, MANDOC_DB, MAXPATHLEN); + + strlcat(mdb.idxn, dirs.paths[i], MAXPATHLEN); + strlcat(mdb.idxn, "/", MAXPATHLEN); + sz2 = strlcat(mdb.idxn, MANDOC_IDX, MAXPATHLEN); + + if (sz1 >= MAXPATHLEN || sz2 >= MAXPATHLEN) { + fprintf(stderr, "%s: path too long\n", + dirs.paths[i]); + exit((int)MANDOCLEVEL_BADARG); + } + + if (mdb.db) + (*mdb.db->close)(mdb.db); + if (mdb.idx) + (*mdb.idx->close)(mdb.idx); + + mdb.db = dbopen(mdb.dbn, flags, 0644, DB_BTREE, &info); + mdb.idx = dbopen(mdb.idxn, flags, 0644, DB_RECNO, NULL); + + if (NULL == mdb.db) { + perror(mdb.dbn); + exit((int)MANDOCLEVEL_SYSERR); + } else if (NULL == mdb.idx) { + perror(mdb.idxn); + exit((int)MANDOCLEVEL_SYSERR); + } + + ofile_free(of); + of = NULL; + + if (-1 == chdir(dirs.paths[i])) { + perror(dirs.paths[i]); + exit((int)MANDOCLEVEL_SYSERR); + } + + ofile_dirbuild(".", "", "", 0, &of); + if (NULL == of) + continue; + + /* + * Go to the root of the respective manual tree. + * This must work or no manuals may be found (they're + * indexed relative to the root). + */ + + if (-1 == chdir(dirs.paths[i])) { + perror(dirs.paths[i]); + exit((int)MANDOCLEVEL_SYSERR); + } + + index_merge(of, mp, &dbuf, &buf, hash, &mdb, &recs); + } + +out: + if (mdb.db) + (*mdb.db->close)(mdb.db); + if (mdb.idx) + (*mdb.idx->close)(mdb.idx); + if (hash) + (*hash->close)(hash); + if (mp) + mparse_free(mp); + + manpath_free(&dirs); + ofile_free(of); + free(buf.cp); + free(dbuf.cp); + free(recs.stack); + + return(MANDOCLEVEL_OK); + +usage: + fprintf(stderr, + "usage: %s [-avvv] [-C file] | dir ... | -t file ...\n" + " -d dir [file ...] | " + "-u dir [file ...]\n", + progname); + + return((int)MANDOCLEVEL_BADARG); +} + +void +index_merge(const struct of *of, struct mparse *mp, + struct buf *dbuf, struct buf *buf, DB *hash, + struct mdb *mdb, struct recs *recs) +{ + recno_t rec; + int ch, skip; + DBT key, val; + struct mdoc *mdoc; + struct man *man; + const char *fn, *msec, *march, *mtitle; + uint64_t mask; + size_t sv; + unsigned seq; + uint64_t vbuf[2]; + char type; + + rec = 0; + for (of = of->first; of; of = of->next) { + fn = of->fname; + + /* + * Try interpreting the file as mdoc(7) or man(7) + * source code, unless it is already known to be + * formatted. Fall back to formatted mode. + */ + + mparse_reset(mp); + mdoc = NULL; + man = NULL; + + if ((MANDOC_SRC & of->src_form || + ! (MANDOC_FORM & of->src_form)) && + MANDOCLEVEL_FATAL > mparse_readfd(mp, -1, fn)) + mparse_result(mp, &mdoc, &man); + + if (NULL != mdoc) { + msec = mdoc_meta(mdoc)->msec; + march = mdoc_meta(mdoc)->arch; + if (NULL == march) + march = ""; + mtitle = mdoc_meta(mdoc)->title; + } else if (NULL != man) { + msec = man_meta(man)->msec; + march = ""; + mtitle = man_meta(man)->title; + } else { + msec = of->sec; + march = of->arch; + mtitle = of->title; + } + + /* + * By default, skip a file if the manual section + * given in the file disagrees with the directory + * where the file is located. + */ + + skip = 0; + assert(of->sec); + assert(msec); + if (strcasecmp(msec, of->sec)) { + if (warnings) + fprintf(stderr, "%s: " + "section \"%s\" manual " + "in \"%s\" directory\n", + fn, msec, of->sec); + skip = 1; + } + + /* + * Manual page directories exist for each kernel + * architecture as returned by machine(1). + * However, many manuals only depend on the + * application architecture as returned by arch(1). + * For example, some (2/ARM) manuals are shared + * across the "armish" and "zaurus" kernel + * architectures. + * A few manuals are even shared across completely + * different architectures, for example fdformat(1) + * on amd64, i386, sparc, and sparc64. + * Thus, warn about architecture mismatches, + * but don't skip manuals for this reason. + */ + + assert(of->arch); + assert(march); + if (strcasecmp(march, of->arch)) { + if (warnings) + fprintf(stderr, "%s: " + "architecture \"%s\" manual " + "in \"%s\" directory\n", + fn, march, of->arch); + march = of->arch; + } + + /* + * By default, skip a file if the title given + * in the file disagrees with the file name. + * If both agree, use the file name as the title, + * because the one in the file usually is all caps. + */ + + assert(of->title); + assert(mtitle); + if (strcasecmp(mtitle, of->title)) { + if (warnings) + fprintf(stderr, "%s: " + "title \"%s\" in file " + "but \"%s\" in filename\n", + fn, mtitle, of->title); + skip = 1; + } else + mtitle = of->title; + + if (skip && !use_all) + continue; + + /* + * The index record value consists of a nil-terminated + * filename, a nil-terminated manual section, and a + * nil-terminated description. Since the description + * may not be set, we set a sentinel to see if we're + * going to write a nil byte in its place. + */ + + dbuf->len = 0; + type = mdoc ? 'd' : (man ? 'a' : 'c'); + buf_appendb(dbuf, &type, 1); + buf_appendb(dbuf, fn, strlen(fn) + 1); + buf_appendb(dbuf, msec, strlen(msec) + 1); + buf_appendb(dbuf, mtitle, strlen(mtitle) + 1); + buf_appendb(dbuf, march, strlen(march) + 1); + + sv = dbuf->len; + + /* + * Collect keyword/mask pairs. + * Each pair will become a new btree node. + */ + + hash_reset(&hash); + if (mdoc) + pmdoc_node(hash, buf, dbuf, + mdoc_node(mdoc), mdoc_meta(mdoc)); + else if (man) + pman_node(hash, buf, dbuf, man_node(man)); + else + pformatted(hash, buf, dbuf, of); + + /* Test mode, do not access any database. */ + + if (NULL == mdb->db || NULL == mdb->idx) + continue; + + /* + * Reclaim an empty index record, if available. + * Use its record number for all new btree nodes. + */ + + if (recs->cur > 0) { + recs->cur--; + rec = recs->stack[(int)recs->cur]; + } else if (recs->last > 0) { + rec = recs->last; + recs->last = 0; + } else + rec++; + vbuf[1] = htobe64(rec); + + /* + * Copy from the in-memory hashtable of pending + * keyword/mask pairs into the database. + */ + + seq = R_FIRST; + while (0 == (ch = (*hash->seq)(hash, &key, &val, seq))) { + seq = R_NEXT; + assert(sizeof(uint64_t) == val.size); + memcpy(&mask, val.data, val.size); + vbuf[0] = htobe64(mask); + val.size = sizeof(vbuf); + val.data = &vbuf; + dbt_put(mdb->db, mdb->dbn, &key, &val); + } + if (ch < 0) { + perror("hash"); + exit((int)MANDOCLEVEL_SYSERR); + } + + /* + * Apply to the index. If we haven't had a description + * set, put an empty one in now. + */ + + if (dbuf->len == sv) + buf_appendb(dbuf, "", 1); + + key.data = &rec; + key.size = sizeof(recno_t); + + val.data = dbuf->cp; + val.size = dbuf->len; + + if (verb) + printf("%s: adding to index\n", fn); + + dbt_put(mdb->idx, mdb->idxn, &key, &val); + } +} + +/* + * Scan through all entries in the index file `idx' and prune those + * entries in `ofile'. + * Pruning consists of removing from `db', then invalidating the entry + * in `idx' (zeroing its value size). + */ +static void +index_prune(const struct of *ofile, struct mdb *mdb, struct recs *recs) +{ + const struct of *of; + const char *fn; + uint64_t vbuf[2]; + unsigned seq, sseq; + DBT key, val; + int ch; + + recs->cur = 0; + seq = R_FIRST; + while (0 == (ch = (*mdb->idx->seq)(mdb->idx, &key, &val, seq))) { + seq = R_NEXT; + assert(sizeof(recno_t) == key.size); + memcpy(&recs->last, key.data, key.size); + + /* Deleted records are zero-sized. Skip them. */ + + if (0 == val.size) + goto cont; + + /* + * Make sure we're sane. + * Read past our mdoc/man/cat type to the next string, + * then make sure it's bounded by a NUL. + * Failing any of these, we go into our error handler. + */ + + fn = (char *)val.data + 1; + if (NULL == memchr(fn, '\0', val.size - 1)) + break; + + /* + * Search for the file in those we care about. + * XXX: build this into a tree. Too slow. + */ + + for (of = ofile->first; of; of = of->next) + if (0 == strcmp(fn, of->fname)) + break; + + if (NULL == of) + continue; + + /* + * Search through the keyword database, throwing out all + * references to our file. + */ + + sseq = R_FIRST; + while (0 == (ch = (*mdb->db->seq)(mdb->db, + &key, &val, sseq))) { + sseq = R_NEXT; + if (sizeof(vbuf) != val.size) + break; + + memcpy(vbuf, val.data, val.size); + if (recs->last != betoh64(vbuf[1])) + continue; + + if ((ch = (*mdb->db->del)(mdb->db, + &key, R_CURSOR)) < 0) + break; + } + + if (ch < 0) { + perror(mdb->dbn); + exit((int)MANDOCLEVEL_SYSERR); + } else if (1 != ch) { + fprintf(stderr, "%s: corrupt database\n", + mdb->dbn); + exit((int)MANDOCLEVEL_SYSERR); + } + + if (verb) + printf("%s: deleting from index\n", fn); + + val.size = 0; + ch = (*mdb->idx->put)(mdb->idx, &key, &val, R_CURSOR); + + if (ch < 0) + break; +cont: + if (recs->cur >= recs->size) { + recs->size += MANDOC_SLOP; + recs->stack = mandoc_realloc(recs->stack, + recs->size * sizeof(recno_t)); + } + + recs->stack[(int)recs->cur] = recs->last; + recs->cur++; + } + + if (ch < 0) { + perror(mdb->idxn); + exit((int)MANDOCLEVEL_SYSERR); + } else if (1 != ch) { + fprintf(stderr, "%s: corrupt index\n", mdb->idxn); + exit((int)MANDOCLEVEL_SYSERR); + } + + recs->last++; +} + +/* + * Grow the buffer (if necessary) and copy in a binary string. + */ +static void +buf_appendb(struct buf *buf, const void *cp, size_t sz) +{ + + /* Overshoot by MANDOC_BUFSZ. */ + + while (buf->len + sz >= buf->size) { + buf->size = buf->len + sz + MANDOC_BUFSZ; + buf->cp = mandoc_realloc(buf->cp, buf->size); + } + + memcpy(buf->cp + (int)buf->len, cp, sz); + buf->len += sz; +} + +/* + * Append a nil-terminated string to the buffer. + * This can be invoked multiple times. + * The buffer string will be nil-terminated. + * If invoked multiple times, a space is put between strings. + */ +static void +buf_append(struct buf *buf, const char *cp) +{ + size_t sz; + + if (0 == (sz = strlen(cp))) + return; + + if (buf->len) + buf->cp[(int)buf->len - 1] = ' '; + + buf_appendb(buf, cp, sz + 1); +} + +/* + * Recursively add all text from a given node. + * This is optimised for general mdoc nodes in this context, which do + * not consist of subexpressions and having a recursive call for n->next + * would be wasteful. + * The "f" variable should be 0 unless called from pmdoc_Nd for the + * description buffer, which does not start at the beginning of the + * buffer. + */ +static void +buf_appendmdoc(struct buf *buf, const struct mdoc_node *n, int f) +{ + + for ( ; n; n = n->next) { + if (n->child) + buf_appendmdoc(buf, n->child, f); + + if (MDOC_TEXT == n->type && f) { + f = 0; + buf_appendb(buf, n->string, + strlen(n->string) + 1); + } else if (MDOC_TEXT == n->type) + buf_append(buf, n->string); + + } +} + +static void +hash_reset(DB **db) +{ + DB *hash; + + if (NULL != (hash = *db)) + (*hash->close)(hash); + + *db = dbopen(NULL, O_CREAT|O_RDWR, 0644, DB_HASH, NULL); + if (NULL == *db) { + perror("hash"); + exit((int)MANDOCLEVEL_SYSERR); + } +} + +/* ARGSUSED */ +static int +pmdoc_head(MDOC_ARGS) +{ + + return(MDOC_HEAD == n->type); +} + +/* ARGSUSED */ +static int +pmdoc_body(MDOC_ARGS) +{ + + return(MDOC_BODY == n->type); +} + +/* ARGSUSED */ +static int +pmdoc_Fd(MDOC_ARGS) +{ + const char *start, *end; + size_t sz; + + if (SEC_SYNOPSIS != n->sec) + return(0); + if (NULL == (n = n->child) || MDOC_TEXT != n->type) + return(0); + + /* + * Only consider those `Fd' macro fields that begin with an + * "inclusion" token (versus, e.g., #define). + */ + if (strcmp("#include", n->string)) + return(0); + + if (NULL == (n = n->next) || MDOC_TEXT != n->type) + return(0); + + /* + * Strip away the enclosing angle brackets and make sure we're + * not zero-length. + */ + + start = n->string; + if ('<' == *start || '"' == *start) + start++; + + if (0 == (sz = strlen(start))) + return(0); + + end = &start[(int)sz - 1]; + if ('>' == *end || '"' == *end) + end--; + + assert(end >= start); + + buf_appendb(buf, start, (size_t)(end - start + 1)); + buf_appendb(buf, "", 1); + return(1); +} + +/* ARGSUSED */ +static int +pmdoc_In(MDOC_ARGS) +{ + + if (NULL == n->child || MDOC_TEXT != n->child->type) + return(0); + + buf_append(buf, n->child->string); + return(1); +} + +/* ARGSUSED */ +static int +pmdoc_Fn(MDOC_ARGS) +{ + struct mdoc_node *nn; + const char *cp; + + nn = n->child; + + if (NULL == nn || MDOC_TEXT != nn->type) + return(0); + + /* .Fn "struct type *name" "char *arg" */ + + cp = strrchr(nn->string, ' '); + if (NULL == cp) + cp = nn->string; + + /* Strip away pointer symbol. */ + + while ('*' == *cp) + cp++; + + /* Store the function name. */ + + buf_append(buf, cp); + hash_put(hash, buf, TYPE_Fn); + + /* Store the function type. */ + + if (nn->string < cp) { + buf->len = 0; + buf_appendb(buf, nn->string, cp - nn->string); + buf_appendb(buf, "", 1); + hash_put(hash, buf, TYPE_Ft); + } + + /* Store the arguments. */ + + for (nn = nn->next; nn; nn = nn->next) { + if (MDOC_TEXT != nn->type) + continue; + buf->len = 0; + buf_append(buf, nn->string); + hash_put(hash, buf, TYPE_Fa); + } + + return(0); +} + +/* ARGSUSED */ +static int +pmdoc_St(MDOC_ARGS) +{ + + if (NULL == n->child || MDOC_TEXT != n->child->type) + return(0); + + buf_append(buf, n->child->string); + return(1); +} + +/* ARGSUSED */ +static int +pmdoc_Xr(MDOC_ARGS) +{ + + if (NULL == (n = n->child)) + return(0); + + buf_appendb(buf, n->string, strlen(n->string)); + + if (NULL != (n = n->next)) { + buf_appendb(buf, ".", 1); + buf_appendb(buf, n->string, strlen(n->string) + 1); + } else + buf_appendb(buf, ".", 2); + + return(1); +} + +/* ARGSUSED */ +static int +pmdoc_Nd(MDOC_ARGS) +{ + + if (MDOC_BODY != n->type) + return(0); + + buf_appendmdoc(dbuf, n->child, 1); + return(1); +} + +/* ARGSUSED */ +static int +pmdoc_Nm(MDOC_ARGS) +{ + + if (SEC_NAME == n->sec) + return(1); + else if (SEC_SYNOPSIS != n->sec || MDOC_HEAD != n->type) + return(0); + + if (NULL == n->child) + buf_append(buf, m->name); + + return(1); +} + +/* ARGSUSED */ +static int +pmdoc_Sh(MDOC_ARGS) +{ + + return(SEC_CUSTOM == n->sec && MDOC_HEAD == n->type); +} + +static void +hash_put(DB *db, const struct buf *buf, uint64_t mask) +{ + uint64_t oldmask; + DBT key, val; + int rc; + + if (buf->len < 2) + return; + + key.data = buf->cp; + key.size = buf->len; + + if ((rc = (*db->get)(db, &key, &val, 0)) < 0) { + perror("hash"); + exit((int)MANDOCLEVEL_SYSERR); + } else if (0 == rc) { + assert(sizeof(uint64_t) == val.size); + memcpy(&oldmask, val.data, val.size); + mask |= oldmask; + } + + val.data = &mask; + val.size = sizeof(uint64_t); + + if ((rc = (*db->put)(db, &key, &val, 0)) < 0) { + perror("hash"); + exit((int)MANDOCLEVEL_SYSERR); + } +} + +static void +dbt_put(DB *db, const char *dbn, DBT *key, DBT *val) +{ + + assert(key->size); + assert(val->size); + + if (0 == (*db->put)(db, key, val, 0)) + return; + + perror(dbn); + exit((int)MANDOCLEVEL_SYSERR); + /* NOTREACHED */ +} + +/* + * Call out to per-macro handlers after clearing the persistent database + * key. If the macro sets the database key, flush it to the database. + */ +static void +pmdoc_node(MDOC_ARGS) +{ + + if (NULL == n) + return; + + switch (n->type) { + case (MDOC_HEAD): + /* FALLTHROUGH */ + case (MDOC_BODY): + /* FALLTHROUGH */ + case (MDOC_TAIL): + /* FALLTHROUGH */ + case (MDOC_BLOCK): + /* FALLTHROUGH */ + case (MDOC_ELEM): + buf->len = 0; + + /* + * Both NULL handlers and handlers returning true + * request using the data. Only skip the element + * when the handler returns false. + */ + + if (NULL != mdocs[n->tok].fp && + 0 == (*mdocs[n->tok].fp)(hash, buf, dbuf, n, m)) + break; + + /* + * For many macros, use the text from all children. + * Set zero flags for macros not needing this. + * In that case, the handler must fill the buffer. + */ + + if (MDOCF_CHILD & mdocs[n->tok].flags) + buf_appendmdoc(buf, n->child, 0); + + /* + * Cover the most common case: + * Automatically stage one string per element. + * Set a zero mask for macros not needing this. + * Additional staging can be done in the handler. + */ + + if (mdocs[n->tok].mask) + hash_put(hash, buf, mdocs[n->tok].mask); + break; + default: + break; + } + + pmdoc_node(hash, buf, dbuf, n->child, m); + pmdoc_node(hash, buf, dbuf, n->next, m); +} + +static int +pman_node(MAN_ARGS) +{ + const struct man_node *head, *body; + const char *start, *sv; + size_t sz; + + if (NULL == n) + return(0); + + /* + * We're only searching for one thing: the first text child in + * the BODY of a NAME section. Since we don't keep track of + * sections in -man, run some hoops to find out whether we're in + * the correct section or not. + */ + + if (MAN_BODY == n->type && MAN_SH == n->tok) { + body = n; + assert(body->parent); + if (NULL != (head = body->parent->head) && + 1 == head->nchild && + NULL != (head = (head->child)) && + MAN_TEXT == head->type && + 0 == strcmp(head->string, "NAME") && + NULL != (body = body->child) && + MAN_TEXT == body->type) { + + assert(body->string); + start = sv = body->string; + + /* + * Go through a special heuristic dance here. + * This is why -man manuals are great! + * (I'm being sarcastic: my eyes are bleeding.) + * Conventionally, one or more manual names are + * comma-specified prior to a whitespace, then a + * dash, then a description. Try to puzzle out + * the name parts here. + */ + + for ( ;; ) { + sz = strcspn(start, " ,"); + if ('\0' == start[(int)sz]) + break; + + buf->len = 0; + buf_appendb(buf, start, sz); + buf_appendb(buf, "", 1); + + hash_put(hash, buf, TYPE_Nm); + + if (' ' == start[(int)sz]) { + start += (int)sz + 1; + break; + } + + assert(',' == start[(int)sz]); + start += (int)sz + 1; + while (' ' == *start) + start++; + } + + buf->len = 0; + + if (sv == start) { + buf_append(buf, start); + return(1); + } + + while (' ' == *start) + start++; + + if (0 == strncmp(start, "-", 1)) + start += 1; + else if (0 == strncmp(start, "\\-\\-", 4)) + start += 4; + else if (0 == strncmp(start, "\\-", 2)) + start += 2; + else if (0 == strncmp(start, "\\(en", 4)) + start += 4; + else if (0 == strncmp(start, "\\(em", 4)) + start += 4; + + while (' ' == *start) + start++; + + sz = strlen(start) + 1; + buf_appendb(dbuf, start, sz); + buf_appendb(buf, start, sz); + + hash_put(hash, buf, TYPE_Nd); + } + } + + for (n = n->child; n; n = n->next) + if (pman_node(hash, buf, dbuf, n)) + return(1); + + return(0); +} + +/* + * Parse a formatted manual page. + * By necessity, this involves rather crude guesswork. + */ +static void +pformatted(DB *hash, struct buf *buf, + struct buf *dbuf, const struct of *of) +{ + FILE *stream; + char *line, *p, *title; + size_t len, plen, titlesz; + + if (NULL == (stream = fopen(of->fname, "r"))) { + if (warnings) + perror(of->fname); + return; + } + + /* + * Always use the title derived from the filename up front, + * do not even try to find it in the file. This also makes + * sure we don't end up with an orphan index record, even if + * the file content turns out to be completely unintelligible. + */ + + buf->len = 0; + buf_append(buf, of->title); + hash_put(hash, buf, TYPE_Nm); + + /* Skip to first blank line. */ + + while (NULL != (line = fgetln(stream, &len))) + if ('\n' == *line) + break; + + /* + * Assume the first line that is not indented + * is the first section header. Skip to it. + */ + + while (NULL != (line = fgetln(stream, &len))) + if ('\n' != *line && ' ' != *line) + break; + + /* + * Read up until the next section into a buffer. + * Strip the leading and trailing newline from each read line, + * appending a trailing space. + * Ignore empty (whitespace-only) lines. + */ + + titlesz = 0; + title = NULL; + + while (NULL != (line = fgetln(stream, &len))) { + if (' ' != *line || '\n' != line[(int)len - 1]) + break; + while (len > 0 && isspace((unsigned char)*line)) { + line++; + len--; + } + if (1 == len) + continue; + title = mandoc_realloc(title, titlesz + len); + memcpy(title + titlesz, line, len); + titlesz += len; + title[(int)titlesz - 1] = ' '; + } + + + /* + * If no page content can be found, or the input line + * is already the next section header, or there is no + * trailing newline, reuse the page title as the page + * description. + */ + + if (NULL == title || '\0' == *title) { + if (warnings) + fprintf(stderr, "%s: cannot find NAME section\n", + of->fname); + buf_appendb(dbuf, buf->cp, buf->size); + hash_put(hash, buf, TYPE_Nd); + fclose(stream); + free(title); + return; + } + + title = mandoc_realloc(title, titlesz + 1); + title[(int)titlesz] = '\0'; + + /* + * Skip to the first dash. + * Use the remaining line as the description (no more than 70 + * bytes). + */ + + if (NULL != (p = strstr(title, "- "))) { + for (p += 2; ' ' == *p || '\b' == *p; p++) + /* Skip to next word. */ ; + } else { + if (warnings) + fprintf(stderr, "%s: no dash in title line\n", + of->fname); + p = title; + } + + plen = strlen(p); + + /* Strip backspace-encoding from line. */ + + while (NULL != (line = memchr(p, '\b', plen))) { + len = line - p; + if (0 == len) { + memmove(line, line + 1, plen--); + continue; + } + memmove(line - 1, line + 1, plen - len); + plen -= 2; + } + + buf_appendb(dbuf, p, plen + 1); + buf->len = 0; + buf_appendb(buf, p, plen + 1); + hash_put(hash, buf, TYPE_Nd); + fclose(stream); + free(title); +} + +static void +ofile_argbuild(int argc, char *argv[], struct of **of) +{ + char buf[MAXPATHLEN]; + const char *sec, *arch, *title; + char *p; + int i, src_form; + struct of *nof; + + for (i = 0; i < argc; i++) { + + /* + * Try to infer the manual section, architecture and + * page title from the path, assuming it looks like + * man*[/]/.<section> or + * cat<section>[/<arch>]/<title>.0 + */ + + if (strlcpy(buf, argv[i], sizeof(buf)) >= sizeof(buf)) { + fprintf(stderr, "%s: path too long\n", argv[i]); + continue; + } + sec = arch = title = ""; + src_form = 0; + p = strrchr(buf, '\0'); + while (p-- > buf) { + if ('\0' == *sec && '.' == *p) { + sec = p + 1; + *p = '\0'; + if ('0' == *sec) + src_form |= MANDOC_FORM; + else if ('1' <= *sec && '9' >= *sec) + src_form |= MANDOC_SRC; + continue; + } + if ('/' != *p) + continue; + if ('\0' == *title) { + title = p + 1; + *p = '\0'; + continue; + } + if (0 == strncmp("man", p + 1, 3)) + src_form |= MANDOC_SRC; + else if (0 == strncmp("cat", p + 1, 3)) + src_form |= MANDOC_FORM; + else + arch = p + 1; + break; + } + if ('\0' == *title) { + if (warnings) + fprintf(stderr, + "%s: cannot deduce title " + "from filename\n", + argv[i]); + title = buf; + } + + /* + * Build the file structure. + */ + + nof = mandoc_calloc(1, sizeof(struct of)); + nof->fname = mandoc_strdup(argv[i]); + nof->sec = mandoc_strdup(sec); + nof->arch = mandoc_strdup(arch); + nof->title = mandoc_strdup(title); + nof->src_form = src_form; + + /* + * Add the structure to the list. + */ + + if (verb > 1) + printf("%s: scheduling\n", argv[i]); + if (NULL == *of) { + *of = nof; + (*of)->first = nof; + } else { + nof->first = (*of)->first; + (*of)->next = nof; + *of = nof; + } + } +} + +/* + * Recursively build up a list of files to parse. + * We use this instead of ftw() and so on because I don't want global + * variables hanging around. + * This ignores the whatis.db and whatis.index files, but assumes that + * everything else is a manual. + * Pass in a pointer to a NULL structure for the first invocation. + */ +static void +ofile_dirbuild(const char *dir, const char* psec, const char *parch, + int p_src_form, struct of **of) +{ + char buf[MAXPATHLEN]; + size_t sz; + DIR *d; + const char *fn, *sec, *arch; + char *p, *q, *suffix; + struct of *nof; + struct dirent *dp; + int src_form; + + if (NULL == (d = opendir(dir))) { + if (warnings) + perror(dir); + return; + } + + while (NULL != (dp = readdir(d))) { + fn = dp->d_name; + + if ('.' == *fn) + continue; + + src_form = p_src_form; + + if (DT_DIR == dp->d_type) { + sec = psec; + arch = parch; + + /* + * By default, only use directories called: + * man<section>/[<arch>/] or + * cat<section>/[<arch>/] + */ + + if ('\0' == *sec) { + if(0 == strncmp("man", fn, 3)) { + src_form |= MANDOC_SRC; + sec = fn + 3; + } else if (0 == strncmp("cat", fn, 3)) { + src_form |= MANDOC_FORM; + sec = fn + 3; + } else { + if (warnings) fprintf(stderr, + "%s/%s: bad section\n", + dir, fn); + if (use_all) + sec = fn; + else + continue; + } + } else if ('\0' == *arch) { + if (NULL != strchr(fn, '.')) { + if (warnings) fprintf(stderr, + "%s/%s: bad architecture\n", + dir, fn); + if (0 == use_all) + continue; + } + arch = fn; + } else { + if (warnings) fprintf(stderr, "%s/%s: " + "excessive subdirectory\n", dir, fn); + if (0 == use_all) + continue; + } + + buf[0] = '\0'; + strlcat(buf, dir, MAXPATHLEN); + strlcat(buf, "/", MAXPATHLEN); + sz = strlcat(buf, fn, MAXPATHLEN); + + if (MAXPATHLEN <= sz) { + if (warnings) fprintf(stderr, "%s/%s: " + "path too long\n", dir, fn); + continue; + } + + if (verb > 1) + printf("%s: scanning\n", buf); + + ofile_dirbuild(buf, sec, arch, src_form, of); + continue; + } + + if (DT_REG != dp->d_type) { + if (warnings) + fprintf(stderr, + "%s/%s: not a regular file\n", + dir, fn); + continue; + } + if (!strcmp(MANDOC_DB, fn) || !strcmp(MANDOC_IDX, fn)) + continue; + if ('\0' == *psec) { + if (warnings) + fprintf(stderr, + "%s/%s: file outside section\n", + dir, fn); + if (0 == use_all) + continue; + } + + /* + * By default, skip files where the file name suffix + * does not agree with the section directory + * they are located in. + */ + + suffix = strrchr(fn, '.'); + if (NULL == suffix) { + if (warnings) + fprintf(stderr, + "%s/%s: no filename suffix\n", + dir, fn); + if (0 == use_all) + continue; + } else if ((MANDOC_SRC & src_form && + strcmp(suffix + 1, psec)) || + (MANDOC_FORM & src_form && + strcmp(suffix + 1, "0"))) { + if (warnings) + fprintf(stderr, + "%s/%s: wrong filename suffix\n", + dir, fn); + if (0 == use_all) + continue; + if ('0' == suffix[1]) + src_form |= MANDOC_FORM; + else if ('1' <= suffix[1] && '9' >= suffix[1]) + src_form |= MANDOC_SRC; + } + + /* + * Skip formatted manuals if a source version is + * available. Ignore the age: it is very unlikely + * that people install newer formatted base manuals + * when they used to have source manuals before, + * and in ports, old manuals get removed on update. + */ + if (0 == use_all && MANDOC_FORM & src_form && + '\0' != *psec) { + buf[0] = '\0'; + strlcat(buf, dir, MAXPATHLEN); + p = strrchr(buf, '/'); + if ('\0' != *parch && NULL != p) + for (p--; p > buf; p--) + if ('/' == *p) + break; + if (NULL == p) + p = buf; + else + p++; + if (0 == strncmp("cat", p, 3)) + memcpy(p, "man", 3); + strlcat(buf, "/", MAXPATHLEN); + sz = strlcat(buf, fn, MAXPATHLEN); + if (sz >= MAXPATHLEN) { + if (warnings) fprintf(stderr, + "%s/%s: path too long\n", + dir, fn); + continue; + } + q = strrchr(buf, '.'); + if (NULL != q && p < q++) { + *q = '\0'; + sz = strlcat(buf, psec, MAXPATHLEN); + if (sz >= MAXPATHLEN) { + if (warnings) fprintf(stderr, + "%s/%s: path too long\n", + dir, fn); + continue; + } + if (0 == access(buf, R_OK)) + continue; + } + } + + buf[0] = '\0'; + assert('.' == dir[0]); + if ('/' == dir[1]) { + strlcat(buf, dir + 2, MAXPATHLEN); + strlcat(buf, "/", MAXPATHLEN); + } + sz = strlcat(buf, fn, MAXPATHLEN); + if (sz >= MAXPATHLEN) { + if (warnings) fprintf(stderr, + "%s/%s: path too long\n", dir, fn); + continue; + } + + nof = mandoc_calloc(1, sizeof(struct of)); + nof->fname = mandoc_strdup(buf); + nof->sec = mandoc_strdup(psec); + nof->arch = mandoc_strdup(parch); + nof->src_form = src_form; + + /* + * Remember the file name without the extension, + * to be used as the page title in the database. + */ + + if (NULL != suffix) + *suffix = '\0'; + nof->title = mandoc_strdup(fn); + + /* + * Add the structure to the list. + */ + + if (verb > 1) + printf("%s: scheduling\n", buf); + + if (NULL == *of) { + *of = nof; + (*of)->first = nof; + } else { + nof->first = (*of)->first; + (*of)->next = nof; + *of = nof; + } + } + + closedir(d); +} + +static void +ofile_free(struct of *of) +{ + struct of *nof; + + if (NULL != of) + of = of->first; + + while (NULL != of) { + nof = of->next; + free(of->fname); + free(of->sec); + free(of->arch); + free(of->title); + free(of); + of = nof; + } +} diff --git a/external/bsd/mdocml/dist/mandocdb.h b/external/bsd/mdocml/dist/mandocdb.h new file mode 100644 index 000000000..a42bcebf9 --- /dev/null +++ b/external/bsd/mdocml/dist/mandocdb.h @@ -0,0 +1,62 @@ +/* $Vendor-Id: mandocdb.h,v 1.5 2011/12/25 16:53:51 schwarze Exp $ */ +/* + * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef MANDOCDB_H +#define MANDOCDB_H + +#define MANDOC_DB "whatis.db" +#define MANDOC_IDX "whatis.index" + +#define TYPE_An 0x0000000000000001ULL +#define TYPE_Ar 0x0000000000000002ULL +#define TYPE_At 0x0000000000000004ULL +#define TYPE_Bsx 0x0000000000000008ULL +#define TYPE_Bx 0x0000000000000010ULL +#define TYPE_Cd 0x0000000000000020ULL +#define TYPE_Cm 0x0000000000000040ULL +#define TYPE_Dv 0x0000000000000080ULL +#define TYPE_Dx 0x0000000000000100ULL +#define TYPE_Em 0x0000000000000200ULL +#define TYPE_Er 0x0000000000000400ULL +#define TYPE_Ev 0x0000000000000800ULL +#define TYPE_Fa 0x0000000000001000ULL +#define TYPE_Fl 0x0000000000002000ULL +#define TYPE_Fn 0x0000000000004000ULL +#define TYPE_Ft 0x0000000000008000ULL +#define TYPE_Fx 0x0000000000010000ULL +#define TYPE_Ic 0x0000000000020000ULL +#define TYPE_In 0x0000000000040000ULL +#define TYPE_Lb 0x0000000000080000ULL +#define TYPE_Li 0x0000000000100000ULL +#define TYPE_Lk 0x0000000000200000ULL +#define TYPE_Ms 0x0000000000400000ULL +#define TYPE_Mt 0x0000000000800000ULL +#define TYPE_Nd 0x0000000001000000ULL +#define TYPE_Nm 0x0000000002000000ULL +#define TYPE_Nx 0x0000000004000000ULL +#define TYPE_Ox 0x0000000008000000ULL +#define TYPE_Pa 0x0000000010000000ULL +#define TYPE_Rs 0x0000000020000000ULL +#define TYPE_Sh 0x0000000040000000ULL +#define TYPE_Ss 0x0000000080000000ULL +#define TYPE_St 0x0000000100000000ULL +#define TYPE_Sy 0x0000000200000000ULL +#define TYPE_Tn 0x0000000400000000ULL +#define TYPE_Va 0x0000000800000000ULL +#define TYPE_Vt 0x0000001000000000ULL +#define TYPE_Xr 0x0000002000000000ULL + +#endif /*!MANDOCDB_H */ diff --git a/external/bsd/mdocml/dist/manpath.c b/external/bsd/mdocml/dist/manpath.c new file mode 100644 index 000000000..3190354d4 --- /dev/null +++ b/external/bsd/mdocml/dist/manpath.c @@ -0,0 +1,225 @@ +/* $Vendor-Id: manpath.c,v 1.8 2011/12/24 22:37:16 kristaps Exp $ */ +/* + * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/param.h> + +#include <assert.h> +#include <ctype.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "mandoc.h" +#include "manpath.h" + +#define MAN_CONF_FILE "/etc/man.conf" +#define MAN_CONF_KEY "_whatdb" + +static void manpath_add(struct manpaths *, const char *); +static void manpath_parseline(struct manpaths *, char *); + +void +manpath_parse(struct manpaths *dirs, const char *file, + char *defp, char *auxp) +{ +#ifdef USE_MANPATH + char cmd[(MAXPATHLEN * 3) + 20]; + FILE *stream; + char *buf; + size_t sz, bsz; + + strlcpy(cmd, "manpath", sizeof(cmd)); + if (file) { + strlcat(cmd, " -C ", sizeof(cmd)); + strlcat(cmd, file, sizeof(cmd)); + } + if (auxp) { + strlcat(cmd, " -m ", sizeof(cmd)); + strlcat(cmd, auxp, sizeof(cmd)); + } + if (defp) { + strlcat(cmd, " -M ", sizeof(cmd)); + strlcat(cmd, defp, sizeof(cmd)); + } + + /* Open manpath(1). Ignore errors. */ + + stream = popen(cmd, "r"); + if (NULL == stream) + return; + + buf = NULL; + bsz = 0; + + /* Read in as much output as we can. */ + + do { + buf = mandoc_realloc(buf, bsz + 1024); + sz = fread(buf + (int)bsz, 1, 1024, stream); + bsz += sz; + } while (sz > 0); + + if ( ! ferror(stream) && feof(stream) && + bsz && '\n' == buf[bsz - 1]) { + buf[bsz - 1] = '\0'; + manpath_parseline(dirs, buf); + } + + free(buf); + pclose(stream); +#else + char *insert; + + /* Always prepend -m. */ + manpath_parseline(dirs, auxp); + + /* If -M is given, it overrides everything else. */ + if (NULL != defp) { + manpath_parseline(dirs, defp); + return; + } + + /* MANPATH and man.conf(5) cooperate. */ + defp = getenv("MANPATH"); + if (NULL == file) + file = MAN_CONF_FILE; + + /* No MANPATH; use man.conf(5) only. */ + if (NULL == defp || '\0' == defp[0]) { + manpath_manconf(dirs, file); + return; + } + + /* Prepend man.conf(5) to MANPATH. */ + if (':' == defp[0]) { + manpath_manconf(dirs, file); + manpath_parseline(dirs, defp); + return; + } + + /* Append man.conf(5) to MANPATH. */ + if (':' == defp[(int)strlen(defp) - 1]) { + manpath_parseline(dirs, defp); + manpath_manconf(dirs, file); + return; + } + + /* Insert man.conf(5) into MANPATH. */ + insert = strstr(defp, "::"); + if (NULL != insert) { + *insert++ = '\0'; + manpath_parseline(dirs, defp); + manpath_manconf(dirs, file); + manpath_parseline(dirs, insert + 1); + return; + } + + /* MANPATH overrides man.conf(5) completely. */ + manpath_parseline(dirs, defp); +#endif +} + +/* + * Parse a FULL pathname from a colon-separated list of arrays. + */ +static void +manpath_parseline(struct manpaths *dirs, char *path) +{ + char *dir; + + if (NULL == path) + return; + + for (dir = strtok(path, ":"); dir; dir = strtok(NULL, ":")) + manpath_add(dirs, dir); +} + +/* + * Add a directory to the array, ignoring bad directories. + * Grow the array one-by-one for simplicity's sake. + */ +static void +manpath_add(struct manpaths *dirs, const char *dir) +{ + char buf[PATH_MAX]; + char *cp; + int i; + + if (NULL == (cp = realpath(dir, buf))) + return; + + for (i = 0; i < dirs->sz; i++) + if (0 == strcmp(dirs->paths[i], dir)) + return; + + dirs->paths = mandoc_realloc + (dirs->paths, + ((size_t)dirs->sz + 1) * sizeof(char *)); + + dirs->paths[dirs->sz++] = mandoc_strdup(cp); +} + +void +manpath_free(struct manpaths *p) +{ + int i; + + for (i = 0; i < p->sz; i++) + free(p->paths[i]); + + free(p->paths); +} + +void +manpath_manconf(struct manpaths *dirs, const char *file) +{ + FILE *stream; + char *p, *q; + size_t len, keysz; + + keysz = strlen(MAN_CONF_KEY); + assert(keysz > 0); + + if (NULL == (stream = fopen(file, "r"))) + return; + + while (NULL != (p = fgetln(stream, &len))) { + if (0 == len || '\n' != p[--len]) + break; + p[len] = '\0'; + while (isspace((unsigned char)*p)) + p++; + if (strncmp(MAN_CONF_KEY, p, keysz)) + continue; + p += keysz; + while (isspace(*p)) + p++; + if ('\0' == *p) + continue; + if (NULL == (q = strrchr(p, '/'))) + continue; + *q = '\0'; + manpath_add(dirs, p); + } + + fclose(stream); +} diff --git a/external/bsd/mdocml/dist/man_argv.c b/external/bsd/mdocml/dist/manpath.h similarity index 60% rename from external/bsd/mdocml/dist/man_argv.c rename to external/bsd/mdocml/dist/manpath.h index 652e30671..24c02f07a 100644 --- a/external/bsd/mdocml/dist/man_argv.c +++ b/external/bsd/mdocml/dist/manpath.h @@ -1,6 +1,7 @@ -/* $Vendor-Id: man_argv.c,v 1.5 2011/01/03 22:42:37 schwarze Exp $ */ +/* $Vendor-Id: manpath.h,v 1.5 2011/12/13 20:56:46 kristaps Exp $ */ /* * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -14,31 +15,24 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif +#ifndef MANPATH_H +#define MANPATH_H -#include <sys/types.h> +/* + * Unsorted list of unique, absolute paths to be searched for manual + * databases. + */ +struct manpaths { + int sz; + char **paths; +}; -#include <assert.h> +__BEGIN_DECLS -#include "mandoc.h" -#include "libman.h" -#include "libmandoc.h" +void manpath_manconf(struct manpaths *, const char *); +void manpath_parse(struct manpaths *, const char *, char *, char *); +void manpath_free(struct manpaths *); +__END_DECLS -int -man_args(struct man *m, int line, int *pos, char *buf, char **v) -{ - char *start; - - assert(*pos); - *v = start = buf + *pos; - assert(' ' != *start); - - if ('\0' == *start) - return(ARGS_EOLN); - - *v = mandoc_getarg(v, m->msg, m->data, line, pos); - return('"' == *start ? ARGS_QWORD : ARGS_WORD); -} +#endif /*!MANPATH_H*/ diff --git a/external/bsd/mdocml/dist/mdoc.3 b/external/bsd/mdocml/dist/mdoc.3 deleted file mode 100644 index dfafbadc5..000000000 --- a/external/bsd/mdocml/dist/mdoc.3 +++ /dev/null @@ -1,348 +0,0 @@ -.\" $Vendor-Id: mdoc.3,v 1.55 2011/01/07 15:07:21 kristaps Exp $ -.\" -.\" Copyright (c) 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> -.\" Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org> -.\" -.\" Permission to use, copy, modify, and distribute this software for any -.\" purpose with or without fee is hereby granted, provided that the above -.\" copyright notice and this permission notice appear in all copies. -.\" -.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -.\" -.Dd January 7, 2011 -.Dt MDOC 3 -.Os -.Sh NAME -.Nm mdoc , -.Nm mdoc_alloc , -.Nm mdoc_endparse , -.Nm mdoc_free , -.Nm mdoc_meta , -.Nm mdoc_node , -.Nm mdoc_parseln , -.Nm mdoc_reset -.Nd mdoc macro compiler library -.Sh SYNOPSIS -.In mandoc.h -.In mdoc.h -.Vt extern const char * const * mdoc_macronames; -.Vt extern const char * const * mdoc_argnames; -.Ft int -.Fo mdoc_addspan -.Fa "struct mdoc *mdoc" -.Fa "const struct tbl_span *span" -.Fc -.Ft "struct mdoc *" -.Fo mdoc_alloc -.Fa "struct regset *regs" -.Fa "void *data" -.Fa "mandocmsg msgs" -.Fc -.Ft int -.Fn mdoc_endparse "struct mdoc *mdoc" -.Ft void -.Fn mdoc_free "struct mdoc *mdoc" -.Ft "const struct mdoc_meta *" -.Fn mdoc_meta "const struct mdoc *mdoc" -.Ft "const struct mdoc_node *" -.Fn mdoc_node "const struct mdoc *mdoc" -.Ft int -.Fo mdoc_parseln -.Fa "struct mdoc *mdoc" -.Fa "int line" -.Fa "char *buf" -.Fc -.Ft int -.Fn mdoc_reset "struct mdoc *mdoc" -.Sh DESCRIPTION -The -.Nm mdoc -library parses lines of -.Xr mdoc 7 -input -into an abstract syntax tree (AST). -.Pp -In general, applications initiate a parsing sequence with -.Fn mdoc_alloc , -parse each line in a document with -.Fn mdoc_parseln , -close the parsing session with -.Fn mdoc_endparse , -operate over the syntax tree returned by -.Fn mdoc_node -and -.Fn mdoc_meta , -then free all allocated memory with -.Fn mdoc_free . -The -.Fn mdoc_reset -function may be used in order to reset the parser for another input -sequence. -.Ss Types -.Bl -ohang -.It Vt struct mdoc -An opaque type. -Its values are only used privately within the library. -.It Vt struct mdoc_node -A parsed node. -See -.Sx Abstract Syntax Tree -for details. -.El -.Ss Functions -If -.Fn mdoc_addspan , -.Fn mdoc_parseln , -or -.Fn mdoc_endparse -return 0, calls to any function but -.Fn mdoc_reset -or -.Fn mdoc_free -will raise an assertion. -.Bl -ohang -.It Fn mdoc_addspan -Add a table span to the parsing stream. -Returns 0 on failure, 1 on success. -.It Fn mdoc_alloc -Allocates a parsing structure. -The -.Fa data -pointer is passed to -.Fa msgs . -Always returns a valid pointer. -The pointer must be freed with -.Fn mdoc_free . -.It Fn mdoc_reset -Reset the parser for another parse routine. -After its use, -.Fn mdoc_parseln -behaves as if invoked for the first time. -If it returns 0, memory could not be allocated. -.It Fn mdoc_free -Free all resources of a parser. -The pointer is no longer valid after invocation. -.It Fn mdoc_parseln -Parse a nil-terminated line of input. -This line should not contain the trailing newline. -Returns 0 on failure, 1 on success. -The input buffer -.Fa buf -is modified by this function. -.It Fn mdoc_endparse -Signals that the parse is complete. -Returns 0 on failure, 1 on success. -.It Fn mdoc_node -Returns the first node of the parse. -.It Fn mdoc_meta -Returns the document's parsed meta-data. -.El -.Ss Variables -.Bl -ohang -.It Va mdoc_macronames -An array of string-ified token names. -.It Va mdoc_argnames -An array of string-ified token argument names. -.El -.Ss Abstract Syntax Tree -The -.Nm -functions produce an abstract syntax tree (AST) describing input in a -regular form. -It may be reviewed at any time with -.Fn mdoc_nodes ; -however, if called before -.Fn mdoc_endparse , -or after -.Fn mdoc_endparse -or -.Fn mdoc_parseln -fail, it may be incomplete. -.Pp -This AST is governed by the ontological -rules dictated in -.Xr mdoc 7 -and derives its terminology accordingly. -.Qq In-line -elements described in -.Xr mdoc 7 -are described simply as -.Qq elements . -.Pp -The AST is composed of -.Vt struct mdoc_node -nodes with block, head, body, element, root and text types as declared -by the -.Va type -field. -Each node also provides its parse point (the -.Va line , -.Va sec , -and -.Va pos -fields), its position in the tree (the -.Va parent , -.Va child , -.Va nchild , -.Va next -and -.Va prev -fields) and some type-specific data, in particular, for nodes generated -from macros, the generating macro in the -.Va tok -field. -.Pp -The tree itself is arranged according to the following normal form, -where capitalised non-terminals represent nodes. -.Pp -.Bl -tag -width "ELEMENTXX" -compact -.It ROOT -\(<- mnode+ -.It mnode -\(<- BLOCK | ELEMENT | TEXT -.It BLOCK -\(<- HEAD [TEXT] (BODY [TEXT])+ [TAIL [TEXT]] -.It ELEMENT -\(<- TEXT* -.It HEAD -\(<- mnode* -.It BODY -\(<- mnode* [ENDBODY mnode*] -.It TAIL -\(<- mnode* -.It TEXT -\(<- [[:printable:],0x1e]* -.El -.Pp -Of note are the TEXT nodes following the HEAD, BODY and TAIL nodes of -the BLOCK production: these refer to punctuation marks. -Furthermore, although a TEXT node will generally have a non-zero-length -string, in the specific case of -.Sq \&.Bd \-literal , -an empty line will produce a zero-length string. -Multiple body parts are only found in invocations of -.Sq \&Bl \-column , -where a new body introduces a new phrase. -.Ss Badly-nested Blocks -The ENDBODY node is available to end the formatting associated -with a given block before the physical end of that block. -It has a non-null -.Va end -field, is of the BODY -.Va type , -has the same -.Va tok -as the BLOCK it is ending, and has a -.Va pending -field pointing to that BLOCK's BODY node. -It is an indirect child of that BODY node -and has no children of its own. -.Pp -An ENDBODY node is generated when a block ends while one of its child -blocks is still open, like in the following example: -.Bd -literal -offset indent -\&.Ao ao -\&.Bo bo ac -\&.Ac bc -\&.Bc end -.Ed -.Pp -This example results in the following block structure: -.Bd -literal -offset indent -BLOCK Ao - HEAD Ao - BODY Ao - TEXT ao - BLOCK Bo, pending -> Ao - HEAD Bo - BODY Bo - TEXT bo - TEXT ac - ENDBODY Ao, pending -> Ao - TEXT bc -TEXT end -.Ed -.Pp -Here, the formatting of the -.Sq \&Ao -block extends from TEXT ao to TEXT ac, -while the formatting of the -.Sq \&Bo -block extends from TEXT bo to TEXT bc. -It renders as follows in -.Fl T Ns Cm ascii -mode: -.Pp -.Dl <ao [bo ac> bc] end -.Pp -Support for badly-nested blocks is only provided for backward -compatibility with some older -.Xr mdoc 7 -implementations. -Using badly-nested blocks is -.Em strongly discouraged : -the -.Fl T Ns Cm html -and -.Fl T Ns Cm xhtml -front-ends are unable to render them in any meaningful way. -Furthermore, behaviour when encountering badly-nested blocks is not -consistent across troff implementations, especially when using multiple -levels of badly-nested blocks. -.Sh EXAMPLES -The following example reads lines from stdin and parses them, operating -on the finished parse tree with -.Fn parsed . -This example does not error-check nor free memory upon failure. -.Bd -literal -offset indent -struct regset regs; -struct mdoc *mdoc; -const struct mdoc_node *node; -char *buf; -size_t len; -int line; - -bzero(®s, sizeof(struct regset)); -line = 1; -mdoc = mdoc_alloc(®s, NULL, NULL); -buf = NULL; -alloc_len = 0; - -while ((len = getline(&buf, &alloc_len, stdin)) >= 0) { - if (len && buflen[len - 1] = '\en') - buf[len - 1] = '\e0'; - if ( ! mdoc_parseln(mdoc, line, buf)) - errx(1, "mdoc_parseln"); - line++; -} - -if ( ! mdoc_endparse(mdoc)) - errx(1, "mdoc_endparse"); -if (NULL == (node = mdoc_node(mdoc))) - errx(1, "mdoc_node"); - -parsed(mdoc, node); -mdoc_free(mdoc); -.Ed -.Pp -To compile this, execute -.Pp -.Dl % cc main.c libmdoc.a libmandoc.a -.Pp -where -.Pa main.c -is the example file. -.Sh SEE ALSO -.Xr mandoc 1 , -.Xr mdoc 7 -.Sh AUTHORS -The -.Nm -library was written by -.An Kristaps Dzonsons Aq kristaps@bsd.lv . diff --git a/external/bsd/mdocml/dist/mdoc.7 b/external/bsd/mdocml/dist/mdoc.7 index 7b0c88cf4..08a613a69 100644 --- a/external/bsd/mdocml/dist/mdoc.7 +++ b/external/bsd/mdocml/dist/mdoc.7 @@ -1,7 +1,7 @@ -.\" $Vendor-Id: mdoc.7,v 1.174 2011/01/04 23:32:21 kristaps Exp $ +.\" $Vendor-Id: mdoc.7,v 1.214 2012/01/03 10:18:05 kristaps Exp $ .\" -.\" Copyright (c) 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> -.\" Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org> +.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> +.\" Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org> .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above @@ -15,286 +15,78 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd January 4, 2011 +.Dd January 3, 2012 .Dt MDOC 7 .Os .Sh NAME .Nm mdoc -.Nd mdoc language reference +.Nd semantic markup language for formatting manual pages .Sh DESCRIPTION The .Nm mdoc -language is used to format -.Bx -.Ux -manuals. -This reference document describes its syntax, structure, and -usage. -The reference implementation is +language supports authoring of manual pages for the +.Xr man 1 +utility by allowing semantic annotations of words, phrases, +page sections and complete manual pages. +Such annotations are used by formatting tools to achieve a uniform +presentation across all manuals written in +.Nm , +and to support hyperlinking if supported by the output medium. +.Pp +This reference document describes the structure of manual pages +and the syntax and usage of the +.Nm +language. +The reference implementation of a parsing and formatting tool is .Xr mandoc 1 ; the .Sx COMPATIBILITY -section describes compatibility with other troff \-mdoc implementations. +section describes compatibility with other implementations. .Pp -An +In an .Nm -document follows simple rules: lines beginning with the control -character -.Sq \. -are parsed for macros. -Other lines are interpreted within the scope of -prior macros: +document, lines beginning with the control character +.Sq \&. +are called +.Dq macro lines . +The first word is the macro name. +It consists of two or three letters. +Most macro names begin with a capital letter. +For a list of available macros, see +.Sx MACRO OVERVIEW . +The words following the macro name are arguments to the macro, optionally +including the names of other, callable macros; see +.Sx MACRO SYNTAX +for details. +.Pp +Lines not beginning with the control character are called +.Dq text lines . +They provide free-form text to be printed; the formatting of the text +depends on the respective processing context: .Bd -literal -offset indent \&.Sh Macro lines change control state. -Other lines are interpreted within the current state. +Text lines are interpreted within the current state. .Ed -.Sh LANGUAGE SYNTAX +.Pp +Many aspects of the basic syntax of the .Nm -documents may contain only graphable 7-bit ASCII characters, the space -character, and, in certain circumstances, the tab character. -All manuals must have -.Ux -line terminators. -.Ss Comments -Text following a -.Sq \e\*q , -whether in a macro or free-form text line, is ignored to the end of -line. -A macro line with only a control character and comment escape, -.Sq \&.\e\*q , -is also ignored. -Macro lines with only a control character and optional whitespace are -stripped from input. -.Ss Reserved Characters -Within a macro line, the following characters are reserved: -.Pp -.Bl -tag -width Ds -offset indent -compact -.It \&. -.Pq period -.It \&, -.Pq comma -.It \&: -.Pq colon -.It \&; -.Pq semicolon -.It \&( -.Pq left-parenthesis -.It \&) -.Pq right-parenthesis -.It \&[ -.Pq left-bracket -.It \&] -.Pq right-bracket -.It \&? -.Pq question -.It \&! -.Pq exclamation -.It \&| -.Pq vertical bar -.El -.Pp -Use of reserved characters is described in -.Sx MACRO SYNTAX . -For general use in macro lines, these characters can either be escaped -with a non-breaking space -.Pq Sq \e& -or, if applicable, an appropriate escape sequence can be used. -.Ss Special Characters -Special characters may occur in both macro and free-form lines. -Sequences begin with the escape character -.Sq \e -followed by either an open-parenthesis -.Sq \&( -for two-character sequences; an open-bracket -.Sq \&[ -for n-character sequences (terminated at a close-bracket -.Sq \&] ) ; -or a single one character sequence. -See -.Xr mandoc_char 7 -for a complete list. -Examples include -.Sq \e(em -.Pq em-dash +language are based on the +.Xr roff 7 +language; see the +.Em LANGUAGE SYNTAX and -.Sq \ee -.Pq back-slash . -.Ss Text Decoration -Terms may be text-decorated using the -.Sq \ef -escape followed by an indicator: B (bold), I (italic), R (Roman), or P -(revert to previous mode): -.Pp -.Dl \efBbold\efR \efIitalic\efP -.Pp -A numerical representation 3, 2, or 1 (bold, italic, and Roman, -respectively) may be used instead. -A text decoration is valid within -the current font scope only: if a macro opens a font scope alongside -its own scope, such as -.Sx \&Bf -.Cm \&Sy , -in-scope invocations of -.Sq \ef -are only valid within the font scope of the macro. -If -.Sq \ef -is specified outside of any font scope, such as in unenclosed, free-form -text, it will affect the remainder of the document. -.Pp -Note this form is -.Em not -recommended for -.Nm , -which encourages semantic annotation. -.Ss Predefined Strings -Historically, -troff -also defined a set of package-specific -.Dq predefined strings , -which, like -.Sx Special Characters , -mark special output characters and strings by way of input codes. -Predefined strings are escaped with the slash-asterisk, -.Sq \e* : -single-character -.Sq \e*X , -two-character -.Sq \e*(XX , -and N-character -.Sq \e*[N] . -See -.Xr mandoc_char 7 -for a complete list. -Examples include -.Sq \e*(Am -.Pq ampersand -and -.Sq \e*(Ba -.Pq vertical bar . -.Ss Whitespace -Whitespace consists of the space character. -In free-form lines, whitespace is preserved within a line; unescaped -trailing spaces are stripped from input (unless in a literal context). -Blank free-form lines, which may include whitespace, are only permitted -within literal contexts. -.Pp -In macro lines, whitespace delimits arguments and is discarded. -If arguments are quoted, whitespace within the quotes is retained. -.Ss Quotation -Macro arguments may be quoted with double-quotes to group -space-delimited terms or to retain blocks of whitespace. -A quoted argument begins with a double-quote preceded by whitespace. -The next double-quote not pairwise adjacent to another double-quote -terminates the literal, regardless of surrounding whitespace. -.Pp -Note that any quoted text, even if it would cause a macro invocation -when unquoted, is considered literal text. -Thus, the following produces -.Sq Op "Fl a" : -.Bd -literal -offset indent -\&.Op "Fl a" -.Ed -.Pp -In free-form mode, quotes are regarded as opaque text. -.Ss Dates -There are several macros in +.Em MACRO SYNTAX +sections in the +.Xr roff 7 +manual for details, in particular regarding +comments, escape sequences, whitespace, and quoting. +However, using +.Xr roff 7 +requests in .Nm -that require a date argument. -The canonical form for dates is the American format: -.Pp -.D1 Cm Month Day , Year -.Pp -The -.Cm Day -value is an optionally zero-padded numeral. -The -.Cm Month -value is the full month name. -The -.Cm Year -value is the full four-digit year. -.Pp -Reduced form dates are broken-down canonical form dates: -.Pp -.D1 Cm Month , Year -.D1 Cm Year -.Pp -Some examples of valid dates follow: -.Pp -.D1 "May, 2009" Pq reduced form -.D1 "2009" Pq reduced form -.D1 "May 20, 2009" Pq canonical form -.Ss Scaling Widths -Many macros support scaled widths for their arguments, such as -stipulating a two-inch list indentation with the following: -.Bd -literal -offset indent -\&.Bl -tag -width 2i -.Ed -.Pp -The syntax for scaled widths is -.Sq Li [+-]?[0-9]*.[0-9]*[:unit:] , -where a decimal must be preceded or proceeded by at least one digit. -Negative numbers, while accepted, are truncated to zero. -The following scaling units are accepted: -.Pp -.Bl -tag -width Ds -offset indent -compact -.It c -centimetre -.It i -inch -.It P -pica (~1/6 inch) -.It p -point (~1/72 inch) -.It f -synonym for -.Sq u -.It v -default vertical span -.It m -width of rendered -.Sq m -.Pq em -character -.It n -width of rendered -.Sq n -.Pq en -character -.It u -default horizontal span -.It M -mini-em (~1/100 em) -.El -.Pp -Using anything other than -.Sq m , -.Sq n , -.Sq u , -or -.Sq v -is necessarily non-portable across output media. -See -.Sx COMPATIBILITY . -.Ss Sentence Spacing -When composing a manual, make sure that sentences end at the end of -a line. -By doing so, front-ends will be able to apply the proper amount of -spacing after the end of sentence (unescaped) period, exclamation mark, -or question mark followed by zero or more non-sentence closing -delimiters ( -.Ns Sq \&) , -.Sq \&] , -.Sq \&' , -.Sq \&" ) . -.Pp -The proper spacing is also intelligently preserved if a sentence ends at -the boundary of a macro line. -For example: -.Pp -.Dl \&Xr mandoc 1 \. -.Dl \&Fl T \&Ns \&Cm ascii \. +documents is discouraged; +.Xr mandoc 1 +supports some of them merely for backward compatibility. .Sh MANUAL STRUCTURE A well-formed .Nm @@ -323,48 +115,49 @@ sections, although this varies between manual sections. .Pp The following is a well-formed skeleton .Nm -file: +file for a utility +.Qq progname : .Bd -literal -offset indent \&.Dd $\&Mdocdate$ -\&.Dt mdoc 7 +\&.Dt PROGNAME section \&.Os \&.Sh NAME -\&.Nm foo -\&.Nd a description goes here -\&.\e\*q .Sh LIBRARY -\&.\e\*q For sections 2, 3, & 9 only. -\&.\e\*q Not used in OpenBSD. +\&.Nm progname +\&.Nd one line about what it does +\&.\e\(dq .Sh LIBRARY +\&.\e\(dq For sections 2, 3, & 9 only. +\&.\e\(dq Not used in OpenBSD. \&.Sh SYNOPSIS -\&.Nm foo +\&.Nm progname \&.Op Fl options \&.Ar \&.Sh DESCRIPTION The \&.Nm utility processes files ... -\&.\e\*q .Sh IMPLEMENTATION NOTES -\&.\e\*q Not used in OpenBSD. -\&.\e\*q .Sh RETURN VALUES -\&.\e\*q For sections 2, 3, & 9 only. -\&.\e\*q .Sh ENVIRONMENT -\&.\e\*q For sections 1, 6, 7, & 8 only. -\&.\e\*q .Sh FILES -\&.\e\*q .Sh EXIT STATUS -\&.\e\*q For sections 1, 6, & 8 only. -\&.\e\*q .Sh EXAMPLES -\&.\e\*q .Sh DIAGNOSTICS -\&.\e\*q For sections 1, 4, 6, 7, & 8 only. -\&.\e\*q .Sh ERRORS -\&.\e\*q For sections 2, 3, & 9 only. -\&.\e\*q .Sh SEE ALSO -\&.\e\*q .Xr foobar 1 -\&.\e\*q .Sh STANDARDS -\&.\e\*q .Sh HISTORY -\&.\e\*q .Sh AUTHORS -\&.\e\*q .Sh CAVEATS -\&.\e\*q .Sh BUGS -\&.\e\*q .Sh SECURITY CONSIDERATIONS -\&.\e\*q Not used in OpenBSD. +\&.\e\(dq .Sh IMPLEMENTATION NOTES +\&.\e\(dq Not used in OpenBSD. +\&.\e\(dq .Sh RETURN VALUES +\&.\e\(dq For sections 2, 3, & 9 only. +\&.\e\(dq .Sh ENVIRONMENT +\&.\e\(dq For sections 1, 6, 7, & 8 only. +\&.\e\(dq .Sh FILES +\&.\e\(dq .Sh EXIT STATUS +\&.\e\(dq For sections 1, 6, & 8 only. +\&.\e\(dq .Sh EXAMPLES +\&.\e\(dq .Sh DIAGNOSTICS +\&.\e\(dq For sections 1, 4, 6, 7, & 8 only. +\&.\e\(dq .Sh ERRORS +\&.\e\(dq For sections 2, 3, & 9 only. +\&.\e\(dq .Sh SEE ALSO +\&.\e\(dq .Xr foobar 1 +\&.\e\(dq .Sh STANDARDS +\&.\e\(dq .Sh HISTORY +\&.\e\(dq .Sh AUTHORS +\&.\e\(dq .Sh CAVEATS +\&.\e\(dq .Sh BUGS +\&.\e\(dq .Sh SECURITY CONSIDERATIONS +\&.\e\(dq Not used in OpenBSD. .Ed .Pp The sections in an @@ -382,6 +175,10 @@ The syntax for this as follows: \&.Nd a one line description .Ed .Pp +Multiple +.Sq \&Nm +names should be separated by commas. +.Pp The .Sx \&Nm macro(s) must precede the @@ -409,16 +206,18 @@ configuration. For the first, utilities (sections 1, 6, and 8), this is generally structured as follows: .Bd -literal -offset indent -\&.Nm foo -\&.Op Fl v -\&.Op Fl o Ar file -\&.Op Ar \&.Nm bar \&.Op Fl v \&.Op Fl o Ar file \&.Op Ar +\&.Nm foo +\&.Op Fl v +\&.Op Fl o Ar file +\&.Op Ar .Ed .Pp +Commands should be ordered alphabetically. +.Pp For the second, function calls (sections 2, 3, 9): .Bd -literal -offset indent \&.In header.h @@ -429,10 +228,18 @@ For the second, function calls (sections 2, 3, 9): \&.Fn bar "const char *src" .Ed .Pp +Ordering of +.Sx \&In , +.Sx \&Vt , +.Sx \&Fn , +and +.Sx \&Fo +macros should follow C header-file conventions. +.Pp And for the third, configurations (section 4): .Bd -literal -offset indent -\&.Cd \*qit* at isa? port 0x2e\*q -\&.Cd \*qit* at isa? port 0x4e\*q +\&.Cd \(dqit* at isa? port 0x2e\(dq +\&.Cd \(dqit* at isa? port 0x4e\(dq .Ed .Pp Manuals not in these sections generally don't need a @@ -477,9 +284,15 @@ or .Sx \&Ss macro or the end of an enclosing block, whichever comes first. .It Em DESCRIPTION -This expands upon the brief, one line description in -.Em NAME . -It usually contains a breakdown of the options (if documenting a +This begins with an expansion of the brief, one line description in +.Em NAME : +.Bd -literal -offset indent +The +\&.Nm +utility does this, that, and the other. +.Ed +.Pp +It usually follows with a breakdown of the options (if documenting a command), such as: .Bd -literal -offset indent The arguments are as follows: @@ -490,6 +303,21 @@ Print verbose information. .Ed .Pp Manuals not documenting a command won't include the above fragment. +.Pp +Since the +.Em DESCRIPTION +section usually contains most of the text of a manual, longer manuals +often use the +.Sx \&Ss +macro to form subsections. +In very long manuals, the +.Em DESCRIPTION +may be split into multiple sections, each started by an +.Sx \&Sh +macro followed by a non-standard section name, and each having +several subsections, like in the present +.Nm +manual. .It Em IMPLEMENTATION NOTES Implementation-specific notes should be kept here. This is useful when implementing standard functions that may have side @@ -551,7 +379,13 @@ This section should exist for most manuals. Cross-references should conventionally be ordered first by section, then alphabetically. .Pp +References to other documentation concerning the topic of the manual page, +for example authoritative books or journal articles, may also be +provided in this section. +.Pp See +.Sx \&Rs +and .Sx \&Xr . .It Em STANDARDS References any standards implemented or used. @@ -562,7 +396,8 @@ section should be used instead. See .Sx \&St . .It Em HISTORY -A brief history of the subject, including where support first appeared. +A brief history of the subject, including where it was first implemented, +and when it was ported to or reimplemented for the operating system at hand. .It Em AUTHORS Credits to the person or persons who wrote the code and/or documentation. Authors should generally be noted by both name and email address. @@ -578,285 +413,132 @@ in this section. .It Em SECURITY CONSIDERATIONS Documents any security precautions that operators should consider. .El -.Sh MACRO SYNTAX -Macros are one to three three characters in length and begin with a -control character, -.Sq \&. , -at the beginning of the line. -An arbitrary amount of whitespace may sit between the control character -and the macro name. -Thus, the following are equivalent: -.Bd -literal -offset indent -\&.Pp -\&.\ \ \ \&Pp -.Ed -.Pp -The syntax of a macro depends on its classification. -In this section, -.Sq \-arg -refers to macro arguments, which may be followed by zero or more -.Sq parm -parameters; -.Sq \&Yo -opens the scope of a macro; and if specified, -.Sq \&Yc -closes it out. -.Pp -The -.Em Callable -column indicates that the macro may also be called by passing its name -as an argument to another macro. -If a macro is not callable but its name appears as an argument -to another macro, it is interpreted as opaque text. -For example, -.Sq \&.Fl \&Sh -produces -.Sq Fl \&Sh . -.Pp -The -.Em Parsed -column indicates whether the macro may call other macros by receiving -their names as arguments. -If a macro is not parsed but the name of another macro appears -as an argument, it is interpreted as opaque text. -.Pp -The -.Em Scope -column, if applicable, describes closure rules. -.Ss Block full-explicit -Multi-line scope closed by an explicit closing macro. -All macros contains bodies; only -.Sx \&Bf -contains a head. -.Bd -literal -offset indent -\&.Yo \(lB\-arg \(lBparm...\(rB\(rB \(lBhead...\(rB -\(lBbody...\(rB -\&.Yc -.Ed -.Pp -.Bl -column -compact -offset indent "MacroX" "CallableX" "ParsedX" "closed by XXX" -.It Em Macro Ta Em Callable Ta Em Parsed Ta Em Scope -.It Sx \&Bd Ta \&No Ta \&No Ta closed by Sx \&Ed -.It Sx \&Bf Ta \&No Ta \&No Ta closed by Sx \&Ef -.It Sx \&Bk Ta \&No Ta \&No Ta closed by Sx \&Ek -.It Sx \&Bl Ta \&No Ta \&No Ta closed by Sx \&El -.It Sx \&Ed Ta \&No Ta \&No Ta opened by Sx \&Bd -.It Sx \&Ef Ta \&No Ta \&No Ta opened by Sx \&Bf -.It Sx \&Ek Ta \&No Ta \&No Ta opened by Sx \&Bk -.It Sx \&El Ta \&No Ta \&No Ta opened by Sx \&Bl +.Sh MACRO OVERVIEW +This overview is sorted such that macros of similar purpose are listed +together, to help find the best macro for any given purpose. +Deprecated macros are not included in the overview, but can be found below +in the alphabetical +.Sx MACRO REFERENCE . +.Ss Document preamble and NAME section macros +.Bl -column "Brq, Bro, Brc" description +.It Sx \&Dd Ta document date: Cm $\&Mdocdate$ | Ar month day , year +.It Sx \&Dt Ta document title: Ar TITLE section Op Ar volume | arch +.It Sx \&Os Ta operating system version: Op Ar system Op Ar version +.It Sx \&Nm Ta document name (one argument) +.It Sx \&Nd Ta document description (one line) .El -.Ss Block full-implicit -Multi-line scope closed by end-of-file or implicitly by another macro. -All macros have bodies; some -.Po -.Sx \&It Fl bullet , -.Fl hyphen , -.Fl dash , -.Fl enum , -.Fl item -.Pc -don't have heads; only one -.Po -.Sx \&It -in -.Sx \&Bl Fl column -.Pc -has multiple heads. -.Bd -literal -offset indent -\&.Yo \(lB\-arg \(lBparm...\(rB\(rB \(lBhead... \(lBTa head...\(rB\(rB -\(lBbody...\(rB -.Ed -.Pp -.Bl -column -compact -offset indent "MacroX" "CallableX" "ParsedX" "closed by XXXXXXXXXXX" -.It Em Macro Ta Em Callable Ta Em Parsed Ta Em Scope -.It Sx \&It Ta \&No Ta Yes Ta closed by Sx \&It , Sx \&El -.It Sx \&Nd Ta \&No Ta \&No Ta closed by Sx \&Sh -.It Sx \&Nm Ta \&No Ta Yes Ta closed by Sx \&Nm , Sx \&Sh , Sx \&Ss -.It Sx \&Sh Ta \&No Ta \&No Ta closed by Sx \&Sh -.It Sx \&Ss Ta \&No Ta \&No Ta closed by Sx \&Sh , Sx \&Ss +.Ss Sections and cross references +.Bl -column "Brq, Bro, Brc" description +.It Sx \&Sh Ta section header (one line) +.It Sx \&Ss Ta subsection header (one line) +.It Sx \&Sx Ta internal cross reference to a section or subsection +.It Sx \&Xr Ta cross reference to another manual page: Ar name section +.It Sx \&Pp , \&Lp Ta start a text paragraph (no arguments) .El -.Pp -Note that the -.Sx \&Nm -macro is a -.Sx Block full-implicit -macro only when invoked as the first macro -in a -.Em SYNOPSIS -section line, else it is -.Sx In-line . -.Ss Block partial-explicit -Like block full-explicit, but also with single-line scope. -Each has at least a body and, in limited circumstances, a head -.Po -.Sx \&Fo , -.Sx \&Eo -.Pc -and/or tail -.Pq Sx \&Ec . -.Bd -literal -offset indent -\&.Yo \(lB\-arg \(lBparm...\(rB\(rB \(lBhead...\(rB -\(lBbody...\(rB -\&.Yc \(lBtail...\(rB - -\&.Yo \(lB\-arg \(lBparm...\(rB\(rB \(lBhead...\(rB \ -\(lBbody...\(rB \&Yc \(lBtail...\(rB -.Ed -.Pp -.Bl -column "MacroX" "CallableX" "ParsedX" "closed by XXXX" -compact -offset indent -.It Em Macro Ta Em Callable Ta Em Parsed Ta Em Scope -.It Sx \&Ac Ta Yes Ta Yes Ta opened by Sx \&Ao -.It Sx \&Ao Ta Yes Ta Yes Ta closed by Sx \&Ac -.It Sx \&Bc Ta Yes Ta Yes Ta closed by Sx \&Bo -.It Sx \&Bo Ta Yes Ta Yes Ta opened by Sx \&Bc -.It Sx \&Brc Ta Yes Ta Yes Ta opened by Sx \&Bro -.It Sx \&Bro Ta Yes Ta Yes Ta closed by Sx \&Brc -.It Sx \&Dc Ta Yes Ta Yes Ta opened by Sx \&Do -.It Sx \&Do Ta Yes Ta Yes Ta closed by Sx \&Dc -.It Sx \&Ec Ta Yes Ta Yes Ta opened by Sx \&Eo -.It Sx \&Eo Ta Yes Ta Yes Ta closed by Sx \&Ec -.It Sx \&Fc Ta Yes Ta Yes Ta opened by Sx \&Fo -.It Sx \&Fo Ta \&No Ta \&No Ta closed by Sx \&Fc -.It Sx \&Oc Ta Yes Ta Yes Ta closed by Sx \&Oo -.It Sx \&Oo Ta Yes Ta Yes Ta opened by Sx \&Oc -.It Sx \&Pc Ta Yes Ta Yes Ta closed by Sx \&Po -.It Sx \&Po Ta Yes Ta Yes Ta opened by Sx \&Pc -.It Sx \&Qc Ta Yes Ta Yes Ta opened by Sx \&Oo -.It Sx \&Qo Ta Yes Ta Yes Ta closed by Sx \&Oc -.It Sx \&Re Ta \&No Ta \&No Ta opened by Sx \&Rs -.It Sx \&Rs Ta \&No Ta \&No Ta closed by Sx \&Re -.It Sx \&Sc Ta Yes Ta Yes Ta opened by Sx \&So -.It Sx \&So Ta Yes Ta Yes Ta closed by Sx \&Sc -.It Sx \&Xc Ta Yes Ta Yes Ta opened by Sx \&Xo -.It Sx \&Xo Ta Yes Ta Yes Ta closed by Sx \&Xc +.Ss Displays and lists +.Bl -column "Brq, Bro, Brc" description +.It Sx \&Bd , \&Ed Ta display block: +.Fl Ar type +.Op Fl offset Ar width +.Op Fl compact +.It Sx \&D1 Ta indented display (one line) +.It Sx \&Dl Ta indented literal display (one line) +.It Sx \&Bl , \&El Ta list block: +.Fl Ar type +.Op Fl width Ar val +.Op Fl offset Ar val +.Op Fl compact +.It Sx \&It Ta list item (syntax depends on Fl Ar type ) +.It Sx \&Ta Ta table cell separator in Sx \&Bl Fl column No lists +.It Sx \&Rs , \&%* , \&Re Ta bibliographic block (references) .El -.Ss Block partial-implicit -Like block full-implicit, but with single-line scope closed by -.Sx Reserved Characters -or end of line. -.Bd -literal -offset indent -\&.Yo \(lB\-arg \(lBval...\(rB\(rB \(lBbody...\(rB \(lBres...\(rB -.Ed -.Pp -.Bl -column "MacroX" "CallableX" "ParsedX" -compact -offset indent -.It Em Macro Ta Em Callable Ta Em Parsed -.It Sx \&Aq Ta Yes Ta Yes -.It Sx \&Bq Ta Yes Ta Yes -.It Sx \&Brq Ta Yes Ta Yes -.It Sx \&D1 Ta \&No Ta \&Yes -.It Sx \&Dl Ta \&No Ta Yes -.It Sx \&Dq Ta Yes Ta Yes -.It Sx \&Op Ta Yes Ta Yes -.It Sx \&Pq Ta Yes Ta Yes -.It Sx \&Ql Ta Yes Ta Yes -.It Sx \&Qq Ta Yes Ta Yes -.It Sx \&Sq Ta Yes Ta Yes -.It Sx \&Vt Ta Yes Ta Yes +.Ss Spacing control +.Bl -column "Brq, Bro, Brc" description +.It Sx \&Pf Ta prefix, no following horizontal space (one argument) +.It Sx \&Ns Ta roman font, no preceding horizontal space (no arguments) +.It Sx \&Ap Ta apostrophe without surrounding whitespace (no arguments) +.It Sx \&Sm Ta switch horizontal spacing mode: Cm on | off +.It Sx \&Bk , \&Ek Ta keep block: Fl words +.It Sx \&br Ta force output line break in text mode (no arguments) +.It Sx \&sp Ta force vertical space: Op Ar height .El -.Pp -Note that the -.Sx \&Vt -macro is a -.Sx Block partial-implicit -only when invoked as the first macro -in a -.Em SYNOPSIS -section line, else it is -.Sx In-line . -.Ss In-line -Closed by -.Sx Reserved Characters , -end of line, fixed argument lengths, and/or subsequent macros. -In-line macros have only text children. -If a number (or inequality) of arguments is -.Pq n , -then the macro accepts an arbitrary number of arguments. -.Bd -literal -offset indent -\&.Yo \(lB\-arg \(lBval...\(rB\(rB \(lBargs...\(rB \(lBres...\(rB - -\&.Yo \(lB\-arg \(lBval...\(rB\(rB \(lBargs...\(rB Yc... - -\&.Yo \(lB\-arg \(lBval...\(rB\(rB arg0 arg1 argN -.Ed -.Pp -.Bl -column "MacroX" "CallableX" "ParsedX" "Arguments" -compact -offset indent -.It Em Macro Ta Em Callable Ta Em Parsed Ta Em Arguments -.It Sx \&%A Ta \&No Ta \&No Ta >0 -.It Sx \&%B Ta \&No Ta \&No Ta >0 -.It Sx \&%C Ta \&No Ta \&No Ta >0 -.It Sx \&%D Ta \&No Ta \&No Ta >0 -.It Sx \&%I Ta \&No Ta \&No Ta >0 -.It Sx \&%J Ta \&No Ta \&No Ta >0 -.It Sx \&%N Ta \&No Ta \&No Ta >0 -.It Sx \&%O Ta \&No Ta \&No Ta >0 -.It Sx \&%P Ta \&No Ta \&No Ta >0 -.It Sx \&%Q Ta \&No Ta \&No Ta >0 -.It Sx \&%R Ta \&No Ta \&No Ta >0 -.It Sx \&%T Ta \&No Ta \&No Ta >0 -.It Sx \&%U Ta \&No Ta \&No Ta >0 -.It Sx \&%V Ta \&No Ta \&No Ta >0 -.It Sx \&Ad Ta Yes Ta Yes Ta n -.It Sx \&An Ta Yes Ta Yes Ta n -.It Sx \&Ap Ta Yes Ta Yes Ta 0 -.It Sx \&Ar Ta Yes Ta Yes Ta n -.It Sx \&At Ta Yes Ta Yes Ta 1 -.It Sx \&Bsx Ta Yes Ta Yes Ta n -.It Sx \&Bt Ta \&No Ta \&No Ta 0 -.It Sx \&Bx Ta Yes Ta Yes Ta n -.It Sx \&Cd Ta Yes Ta Yes Ta >0 -.It Sx \&Cm Ta Yes Ta Yes Ta n -.It Sx \&Db Ta \&No Ta \&No Ta 1 -.It Sx \&Dd Ta \&No Ta \&No Ta n -.It Sx \&Dt Ta \&No Ta \&No Ta n -.It Sx \&Dv Ta Yes Ta Yes Ta n -.It Sx \&Dx Ta Yes Ta Yes Ta n -.It Sx \&Em Ta Yes Ta Yes Ta >0 -.It Sx \&En Ta \&No Ta \&No Ta 0 -.It Sx \&Er Ta Yes Ta Yes Ta >0 -.It Sx \&Es Ta \&No Ta \&No Ta 0 -.It Sx \&Ev Ta Yes Ta Yes Ta n -.It Sx \&Ex Ta \&No Ta \&No Ta n -.It Sx \&Fa Ta Yes Ta Yes Ta n -.It Sx \&Fd Ta \&No Ta \&No Ta >0 -.It Sx \&Fl Ta Yes Ta Yes Ta n -.It Sx \&Fn Ta Yes Ta Yes Ta >0 -.It Sx \&Fr Ta \&No Ta \&No Ta n -.It Sx \&Ft Ta Yes Ta Yes Ta n -.It Sx \&Fx Ta Yes Ta Yes Ta n -.It Sx \&Hf Ta \&No Ta \&No Ta n -.It Sx \&Ic Ta Yes Ta Yes Ta >0 -.It Sx \&In Ta \&No Ta \&No Ta n -.It Sx \&Lb Ta \&No Ta \&No Ta 1 -.It Sx \&Li Ta Yes Ta Yes Ta n -.It Sx \&Lk Ta Yes Ta Yes Ta n -.It Sx \&Lp Ta \&No Ta \&No Ta 0 -.It Sx \&Ms Ta Yes Ta Yes Ta >0 -.It Sx \&Mt Ta Yes Ta Yes Ta >0 -.It Sx \&Nm Ta Yes Ta Yes Ta n -.It Sx \&No Ta Yes Ta Yes Ta 0 -.It Sx \&Ns Ta Yes Ta Yes Ta 0 -.It Sx \&Nx Ta Yes Ta Yes Ta n -.It Sx \&Os Ta \&No Ta \&No Ta n -.It Sx \&Ot Ta \&No Ta \&No Ta n -.It Sx \&Ox Ta Yes Ta Yes Ta n -.It Sx \&Pa Ta Yes Ta Yes Ta n -.It Sx \&Pf Ta Yes Ta Yes Ta 1 -.It Sx \&Pp Ta \&No Ta \&No Ta 0 -.It Sx \&Rv Ta \&No Ta \&No Ta n -.It Sx \&Sm Ta \&No Ta \&No Ta 1 -.It Sx \&St Ta \&No Ta Yes Ta 1 -.It Sx \&Sx Ta Yes Ta Yes Ta >0 -.It Sx \&Sy Ta Yes Ta Yes Ta >0 -.It Sx \&Tn Ta Yes Ta Yes Ta >0 -.It Sx \&Ud Ta \&No Ta \&No Ta 0 -.It Sx \&Ux Ta Yes Ta Yes Ta n -.It Sx \&Va Ta Yes Ta Yes Ta n -.It Sx \&Vt Ta Yes Ta Yes Ta >0 -.It Sx \&Xr Ta Yes Ta Yes Ta >0 -.It Sx \&br Ta \&No Ta \&No Ta 0 -.It Sx \&sp Ta \&No Ta \&No Ta 1 +.Ss Semantic markup for command line utilities: +.Bl -column "Brq, Bro, Brc" description +.It Sx \&Nm Ta start a SYNOPSIS block with the name of a utility +.It Sx \&Fl Ta command line options (flags) (>=0 arguments) +.It Sx \&Cm Ta command modifier (>0 arguments) +.It Sx \&Ar Ta command arguments (>=0 arguments) +.It Sx \&Op , \&Oo , \&Oc Ta optional syntax elements (enclosure) +.It Sx \&Ic Ta internal or interactive command (>0 arguments) +.It Sx \&Ev Ta environmental variable (>0 arguments) +.It Sx \&Pa Ta file system path (>=0 arguments) .El -.Sh REFERENCE +.Ss Semantic markup for function libraries: +.Bl -column "Brq, Bro, Brc" description +.It Sx \&Lb Ta function library (one argument) +.It Sx \&In Ta include file (one argument) +.It Sx \&Ft Ta function type (>0 arguments) +.It Sx \&Fo , \&Fc Ta function block: Ar funcname +.It Sx \&Fn Ta function name: +.Op Ar functype +.Ar funcname +.Oo +.Op Ar argtype +.Ar argname +.Oc +.It Sx \&Fa Ta function argument (>0 arguments) +.It Sx \&Vt Ta variable type (>0 arguments) +.It Sx \&Va Ta variable name (>0 arguments) +.It Sx \&Dv Ta defined variable or preprocessor constant (>0 arguments) +.It Sx \&Er Ta error constant (>0 arguments) +.It Sx \&Ev Ta environmental variable (>0 arguments) +.El +.Ss Various semantic markup: +.Bl -column "Brq, Bro, Brc" description +.It Sx \&An Ta author name (>0 arguments) +.It Sx \&Lk Ta hyperlink: Ar uri Op Ar name +.It Sx \&Mt Ta Do mailto Dc hyperlink: Ar address +.It Sx \&Cd Ta kernel configuration declaration (>0 arguments) +.It Sx \&Ad Ta memory address (>0 arguments) +.It Sx \&Ms Ta mathematical symbol (>0 arguments) +.It Sx \&Tn Ta tradename (>0 arguments) +.El +.Ss Physical markup +.Bl -column "Brq, Bro, Brc" description +.It Sx \&Em Ta italic font or underline (emphasis) (>0 arguments) +.It Sx \&Sy Ta boldface font (symbolic) (>0 arguments) +.It Sx \&Li Ta typewriter font (literal) (>0 arguments) +.It Sx \&No Ta return to roman font (normal) (no arguments) +.It Sx \&Bf , \&Ef Ta font block: +.Op Fl Ar type | Cm \&Em | \&Li | \&Sy +.El +.Ss Physical enclosures +.Bl -column "Brq, Bro, Brc" description +.It Sx \&Dq , \&Do , \&Dc Ta enclose in typographic double quotes: Dq text +.It Sx \&Qq , \&Qo , \&Qc Ta enclose in typewriter double quotes: Qq text +.It Sx \&Sq , \&So , \&Sc Ta enclose in single quotes: Sq text +.It Sx \&Ql Ta single-quoted literal text: Ql text +.It Sx \&Pq , \&Po , \&Pc Ta enclose in parentheses: Pq text +.It Sx \&Bq , \&Bo , \&Bc Ta enclose in square brackets: Bq text +.It Sx \&Brq , \&Bro , \&Brc Ta enclose in curly braces: Brq text +.It Sx \&Aq , \&Ao , \&Ac Ta enclose in angle brackets: Aq text +.It Sx \&Eo , \&Ec Ta generic enclosure +.El +.Ss Text production +.Bl -column "Brq, Bro, Brc" description +.It Sx \&Ex Fl std Ta standard command exit values: Op Ar utility ... +.It Sx \&Rv Fl std Ta standard function return values: Op Ar function ... +.It Sx \&St Ta reference to a standards document (one argument) +.It Sx \&Ux Ta Ux +.It Sx \&At Ta At +.It Sx \&Bx Ta Bx +.It Sx \&Bsx Ta Bsx +.It Sx \&Nx Ta Nx +.It Sx \&Fx Ta Fx +.It Sx \&Ox Ta Ox +.It Sx \&Dx Ta Dx +.El +.Sh MACRO REFERENCE This section is a canonical reference of all macros, arranged alphabetically. For the scoping of individual macros, see @@ -884,8 +566,10 @@ block. Publication date of an .Sx \&Rs block. -This should follow the reduced or canonical form syntax described in -.Sx Dates . +Recommended formats of arguments are +.Ar month day , year +or just +.Ar year . .Ss \&%I Publisher or issuer name of an .Sx \&Rs @@ -943,6 +627,8 @@ Examples: .Dl \&.Ad 0x00000000 .Ss \&An Author name. +Can be used both for the authors of the program, function, or driver +documented in the manual, or for the authors of the manual itself. Requires either the name of an author or one of the following arguments: .Pp .Bl -tag -width "-nosplitX" -offset indent -compact @@ -1013,9 +699,17 @@ If an argument is not provided, the string is used as a default. .Pp Examples: -.Dl \&.Fl o \&Ns \&Ar file1 -.Dl \&.Ar -.Dl \&.Ar arg1 , arg2 . +.Dl ".Fl o Ar file" +.Dl ".Ar" +.Dl ".Ar arg1 , arg2 ." +.Pp +The arguments to the +.Sx \&Ar +macro are names and placeholders for command arguments; +for fixed strings to be passed verbatim as arguments, use +.Sx \&Fl +or +.Sx \&Cm . .Ss \&At Formats an AT&T version. Accepts one optional argument: @@ -1024,6 +718,8 @@ Accepts one optional argument: .It Cm v[1-7] | 32v A version of .At . +.It Cm III +.At III . .It Cm V[.[1-4]]? A version of .At V . @@ -1033,6 +729,7 @@ Note that these arguments do not begin with a hyphen. .Pp Examples: .Dl \&.At +.Dl \&.At III .Dl \&.At V.1 .Pp See also @@ -1061,7 +758,7 @@ Its syntax is as follows: .Pp Display blocks are used to select a different indentation and justification than the one used by the surrounding text. -They may contain both macro lines and free-form text lines. +They may contain both macro lines and text lines. By default, a display block is preceded by a vertical space. .Pp The @@ -1069,20 +766,27 @@ The must be one of the following: .Bl -tag -width 13n -offset indent .It Fl centered -Centre-justify each line. +Produce one output line from each input line, and centre-justify each line. Using this display type is not recommended; many .Nm implementations render it poorly. .It Fl filled -Left- and right-justify the block. +Change the positions of line breaks to fill each line, and left- and +right-justify the resulting block. .It Fl literal -Do not justify the block at all. +Produce one output line from each input line, +and do not justify the block at all. Preserve white space as it appears in the input. +Always use a constant-width font. +Use this for displaying source code. .It Fl ragged -Only left-justify the block. +Change the positions of line breaks to fill each line, and left-justify +the resulting block. .It Fl unfilled -An alias for -.Fl literal . +The same as +.Fl literal , +but using the same font as for normal text, which is a variable width font +if supported by the output device. .El .Pp The @@ -1098,7 +802,7 @@ which may be one of the following: .It One of the pre-defined strings .Cm indent , -the width of standard indentation; +the width of a standard indentation (six constant width characters); .Cm indent-two , twice .Cm indent ; @@ -1176,9 +880,10 @@ See also and .Sx \&Sy . .Ss \&Bk -Keep the output generated from each macro input line together -on one single output line. -Line breaks in free-form text lines are unaffected. +For each macro, keep its output together on the same output line, +until the end of the macro or the end of the input line is reached, +whichever comes first. +Line breaks in text lines are unaffected. The syntax is as follows: .Pp .D1 Pf \. Sx \&Bk Fl words @@ -1274,9 +979,12 @@ except that dashes are used in place of bullets. Like .Fl inset , except that item heads are not parsed for macro invocations. -.\" but with additional formatting to the head. +Most often used in the +.Em DIAGNOSTICS +section with error constants in the item heads. .It Fl enum A numbered list. +No item heads can be specified. Formatted like .Fl bullet , except that cardinal numbers are used in place of bullets, @@ -1316,6 +1024,13 @@ this head on the same output line. Otherwise, the body starts on the output line following the head. .El .Pp +Lists may be nested within lists and displays. +Nesting of +.Fl column +and +.Fl enum +lists may not be portable. +.Pp See also .Sx \&El and @@ -1392,12 +1107,13 @@ and .Sx \&Ux . .Ss \&Bt Prints -.Dq is currently in beta test . +.Dq is currently in beta test. .Ss \&Bx Format the BSD version provided as an argument, or a default value if no argument is provided. .Pp Examples: +.Dl \&.Bx 4.3 Tahoe .Dl \&.Bx 4.4 .Dl \&.Bx .Pp @@ -1414,6 +1130,7 @@ and Kernel configuration declaration. This denotes strings accepted by .Xr config 8 . +It is most often used in section 4 manual pages. .Pp Examples: .Dl \&.Cd device le0 at scode? @@ -1426,14 +1143,17 @@ declarations. This practise is discouraged. .Ss \&Cm Command modifiers. -Useful when specifying configuration options or keys. +Typically used for fixed strings passed as arguments, unless +.Sx \&Fl +is more appropriate. +Also useful when specifying configuration options or keys. .Pp Examples: -.Dl \&.Cm ControlPath -.Dl \&.Cm ControlMaster -.Pp -See also -.Sx \&Fl . +.Dl ".Nm mt Fl f Ar device Cm rewind" +.Dl ".Nm ps Fl o Cm pid , Ns Cm command" +.Dl ".Nm dd Cm if= Ns Ar file1 Cm of= Ns Ar file2" +.Dl ".Cm IdentityFile Pa ~/.ssh/id_rsa" +.Dl ".Cm LogLevel Dv DEBUG" .Ss \&D1 One-line indented display. This is formatted by the default rules and is useful for simple indented @@ -1467,17 +1187,36 @@ This is the mandatory first macro of any manual. Its syntax is as follows: .Pp -.D1 Pf \. Sx \&Dd Op Ar date +.D1 Pf \. Sx \&Dd Ar month day , year .Pp The -.Ar date -may be either -.Ar $\&Mdocdate$ , -which signifies the current manual revision date dictated by +.Ar month +is the full English month name, the +.Ar day +is an optionally zero-padded numeral, and the +.Ar year +is the full four-digit year. +.Pp +Other arguments are not portable; the +.Xr mandoc 1 +utility handles them as follows: +.Bl -dash -offset 3n -compact +.It +To have the date automatically filled in by the +.Ox +version of .Xr cvs 1 , -or instead a valid canonical date as specified by -.Sx Dates . -If a date does not conform or is empty, the current date is used. +the special string +.Dq $\&Mdocdate$ +can be given as an argument. +.It +A few alternative date formats are accepted as well +and converted to the standard form. +.It +If a date string cannot be parsed, it is used verbatim. +.It +If no date string is given, the current date is used. +.El .Pp Examples: .Dl \&.Dd $\&Mdocdate$ @@ -1543,7 +1282,8 @@ Its syntax is as follows: .Ar title .Oo .Ar section -.Op Ar volume | arch +.Op Ar volume +.Op Ar arch .Oc .Oc .Ed @@ -1624,42 +1364,19 @@ or .Ar CON .Pq contributed manuals . .It Ar arch -This specifies a specific relevant architecture. -If -.Ar volume -is not provided, it may be used in its place, else it may be used -subsequent that. -It, too, is optional. -It must be one of -.Ar alpha , -.Ar amd64 , -.Ar amiga , -.Ar arc , -.Ar arm , -.Ar armish , -.Ar aviion , -.Ar hp300 , -.Ar hppa , -.Ar hppa64 , -.Ar i386 , -.Ar landisk , -.Ar loongson , -.Ar luna88k , -.Ar mac68k , -.Ar macppc , -.Ar mips64 , -.Ar mvme68k , -.Ar mvme88k , -.Ar mvmeppc , -.Ar pmax , -.Ar sgi , -.Ar socppc , -.Ar sparc , -.Ar sparc64 , -.Ar sun3 , -.Ar vax , +This specifies the machine architecture a manual page applies to, +where relevant, for example +.Cm alpha , +.Cm amd64 , +.Cm i386 , or -.Ar zaurus . +.Cm sparc64 . +The list of supported architectures varies by operating system. +For the full list of all architectures recognized by +.Xr mandoc 1 , +see the file +.Pa arch.in +in the source distribution. .El .Pp Examples: @@ -1672,14 +1389,21 @@ See also and .Sx \&Os . .Ss \&Dv -Defined variables such as preprocessor constants. +Defined variables such as preprocessor constants, constant symbols, +enumeration values, and so on. .Pp Examples: +.Dl \&.Dv NULL .Dl \&.Dv BUFSIZ .Dl \&.Dv STDOUT_FILENO .Pp See also -.Sx \&Er . +.Sx \&Er +and +.Sx \&Ev +for special-purpose constants and +.Sx \&Va +for variable symbols. .Ss \&Dx Format the DragonFly BSD version provided as an argument, or a default value if no argument is provided. @@ -1727,9 +1451,12 @@ See also and .Sx \&It . .Ss \&Em -Denotes text that should be emphasised. +Denotes text that should be +.Em emphasised . Note that this is a presentation term and should not be used for stylistically decorating technical terms. +Depending on the output device, this is usually represented +using an italic font or underlined characters. .Pp Examples: .Dl \&.Em Warnings! @@ -1737,9 +1464,10 @@ Examples: .Pp See also .Sx \&Bf , -.Sx \&Sy , +.Sx \&Li , +.Sx \&No , and -.Sx \&Li . +.Sx \&Sy . .Ss \&En This macro is obsolete and not implemented in .Xr mandoc 1 . @@ -1755,14 +1483,18 @@ argument is used as the enclosure head, for example, specifying \e(lq will emulate .Sx \&Do . .Ss \&Er -Display error constants. +Error constants for definitions of the +.Va errno +libc global variable. +This is most often used in section 2 and 3 manual pages. .Pp Examples: .Dl \&.Er EPERM .Dl \&.Er ENOENT .Pp See also -.Sx \&Dv . +.Sx \&Dv +for general constants. .Ss \&Es This macro is obsolete and not implemented. .Ss \&Ev @@ -1772,17 +1504,26 @@ Environmental variables such as those specified in Examples: .Dl \&.Ev DISPLAY .Dl \&.Ev PATH +.Pp +See also +.Sx \&Dv +for general constants. .Ss \&Ex -Insert a standard sentence regarding exit values. +Insert a standard sentence regarding command exit values of 0 on success +and >0 on failure. +This is most often used in section 1, 6, and 8 manual pages. Its syntax is as follows: .Pp -.D1 Pf \. Sx \&Ex Fl std Op Ar utility +.D1 Pf \. Sx \&Ex Fl std Op Ar utility ... .Pp -When +If .Ar utility is not specified, the document's name set by .Sx \&Nm is used. +Multiple +.Ar utility +arguments are treated as separate utilities. .Pp See also .Sx \&Rv . @@ -1831,7 +1572,7 @@ See also and .Sx \&In . .Ss \&Fl -Command-line flag. +Command-line flag or option. Used when listing arguments to command-line utilities. Prints a fixed-width hyphen .Sq \- @@ -1841,10 +1582,11 @@ If the argument is a macro, a hyphen is prefixed to the subsequent macro output. .Pp Examples: -.Dl \&.Fl a b c -.Dl \&.Fl \&Pf a b -.Dl \&.Fl -.Dl \&.Op \&Fl o \&Ns \&Ar file +.Dl ".Fl R Op Fl H | L | P" +.Dl ".Op Fl 1AaCcdFfgHhikLlmnopqRrSsTtux" +.Dl ".Fl type Cm d Fl name Pa CVS" +.Dl ".Fl Ar signal_number" +.Dl ".Fl o Fl" .Pp See also .Sx \&Cm . @@ -1853,19 +1595,24 @@ A function name. Its syntax is as follows: .Bd -ragged -offset indent .Pf \. Ns Sx \&Fn -.Op Cm functype -.Cm funcname -.Op Oo Cm argtype Oc Cm argname +.Op Ar functype +.Ar funcname +.Op Oo Ar argtype Oc Ar argname .Ed .Pp Function arguments are surrounded in parenthesis and are delimited by commas. If no arguments are specified, blank parenthesis are output. +In the +.Em SYNOPSIS +section, this macro starts a new output line, +and a blank line is automatically inserted between function definitions. .Pp Examples: -.Dl \&.Fn "int funcname" "int arg0" "int arg1" -.Dl \&.Fn funcname "int arg0" +.Dl \&.Fn \(dqint funcname\(dq \(dqint arg0\(dq \(dqint arg1\(dq +.Dl \&.Fn funcname \(dqint arg0\(dq .Dl \&.Fn funcname arg0 +.Pp .Bd -literal -offset indent -compact \&.Ft functype \&.Fn funcname @@ -1875,7 +1622,8 @@ When referring to a function documented in another manual page, use .Sx \&Xr instead. See also -.Sx MANUAL STRUCTURE +.Sx MANUAL STRUCTURE , +.Sx \&Fo , and .Sx \&Ft . .Ss \&Fo @@ -1884,17 +1632,17 @@ This is a multi-line version of .Sx \&Fn . Its syntax is as follows: .Pp -.D1 Pf \. Sx \&Fo Cm funcname +.D1 Pf \. Sx \&Fo Ar funcname .Pp Invocations usually occur in the following context: .Bd -ragged -offset indent -.Pf \. Sx \&Ft Cm functype +.Pf \. Sx \&Ft Ar functype .br -.Pf \. Sx \&Fo Cm funcname +.Pf \. Sx \&Fo Ar funcname .br -.Pf \. Sx \&Fa Oo Cm argtype Oc Cm argname +.Pf \. Sx \&Fa Oo Ar argtype Oc Ar argname .br -\.\.\. +\&.\.\. .br .Pf \. Sx \&Fc .Ed @@ -1902,6 +1650,7 @@ Invocations usually occur in the following context: A .Sx \&Fo scope is closed by +.Sx \&Fc . .Pp See also .Sx MANUAL STRUCTURE , @@ -1909,11 +1658,23 @@ See also .Sx \&Fc , and .Sx \&Ft . +.Ss \&Fr +This macro is obsolete and not implemented in +.Xr mandoc 1 . +.Pp +It was used to show function return values. +The syntax was: +.Pp +.Dl Pf . Sx \&Fr Ar value .Ss \&Ft A function type. Its syntax is as follows: .Pp -.D1 Pf \. Sx \&Ft Cm functype +.D1 Pf \. Sx \&Ft Ar functype +.Pp +In the +.Em SYNOPSIS +section, a new output line is started after this macro. .Pp Examples: .Dl \&.Ft int @@ -1947,7 +1708,13 @@ See also and .Sx \&Ux . .Ss \&Hf -This macro is obsolete and not implemented. +This macro is not implemented in +.Xr mandoc 1 . +.Pp +It was used to include the contents of a (header) file literally. +The syntax was: +.Pp +.Dl Pf . Sx \&Hf Ar filename .Ss \&Ic Designate an internal or interactive command. This is similar to @@ -1955,6 +1722,7 @@ This is similar to but used for instructions rather than values. .Pp Examples: +.Dl \&.Ic :wq .Dl \&.Ic hash .Dl \&.Ic alias .Pp @@ -1969,15 +1737,17 @@ macro is used when referring to specific instructions. An .Dq include file. -In the +When invoked as the first macro on an input line in the .Em SYNOPSIS -section (only if invoked as the line macro), the first argument is -preceded by +section, the argument is displayed in angle brackets +and preceded by .Dq #include , -the arguments is enclosed in angle brackets. +and a blank line is inserted in front if there is a preceding +function declaration. +This is most often used in section 2, 3, and 9 manual pages. .Pp Examples: -.Dl \&.In sys/types +.Dl \&.In sys/types.h .Pp See also .Sx MANUAL STRUCTURE . @@ -1994,7 +1764,7 @@ and .Fl diag have the following syntax: .Pp -.D1 Pf \. Sx \&It Cm args +.D1 Pf \. Sx \&It Ar args .Pp Lists of type .Fl bullet , @@ -2031,31 +1801,27 @@ The list is the most complicated. Its syntax is as follows: .Pp -.D1 Pf \. Sx \&It Op Cm args +.D1 Pf \. Sx \&It Ar cell Op <TAB> Ar cell ... +.D1 Pf \. Sx \&It Ar cell Op Sx \&Ta Ar cell ... .Pp -The -.Cm args -are phrases, a mix of macros and text corresponding to a line column, -delimited by tabs or the special -.Sq \&Ta -pseudo-macro. -Lines subsequent the +The arguments consist of one or more lines of text and macros +representing a complete table line. +Cells within the line are delimited by tabs or by the special +.Sx \&Ta +block macro. +The tab cell delimiter may only be used within the .Sx \&It -are interpreted within the scope of the last phrase. -Calling the pseudo-macro -.Sq \&Ta -will open a new phrase scope (this must occur on a macro line to be -interpreted as a macro). -Note that the tab phrase delimiter may only be used within the +line itself; on following lines, only the +.Sx \&Ta +macro can be used to delimit cells, and +.Sx \&Ta +is only recognised as a macro when called by other macros, +not as the first macro on a line. +.Pp +Note that quoted strings may span tab-delimited cells on an .Sx \&It -line itself. -Subsequent this, only the -.Sq \&Ta -pseudo-macro may be used to delimit phrases. -Furthermore, note that quoted sections propagate over tab-delimited -phrases on an -.Sx \&It , -for example, +line. +For example, .Pp .Dl .It \(dqcol1 ; <TAB> col2 ;\(dq \&; .Pp @@ -2067,10 +1833,10 @@ See also Specify a library. The syntax is as follows: .Pp -.D1 Pf \. Sx \&Lb Cm library +.D1 Pf \. Sx \&Lb Ar library .Pp The -.Cm library +.Ar library parameter may be a system library, such as .Cm libz or @@ -2087,23 +1853,29 @@ Examples: .Dl \&.Lb libz .Dl \&.Lb mdoc .Ss \&Li -Denotes text that should be in a literal font mode. +Denotes text that should be in a +.Li literal +font mode. Note that this is a presentation term and should not be used for stylistically decorating technical terms. .Pp +On terminal output devices, this is often indistinguishable from +normal text. +.Pp See also .Sx \&Bf , -.Sx \&Sy , +.Sx \&Em , +.Sx \&No , and -.Sx \&Em . +.Sx \&Sy . .Ss \&Lk Format a hyperlink. Its syntax is as follows: .Pp -.D1 Pf \. Sx \&Lk Cm uri Op Cm name +.D1 Pf \. Sx \&Lk Ar uri Op Ar name .Pp Examples: -.Dl \&.Lk http://bsd.lv \*qThe BSD.lv Project\*q +.Dl \&.Lk http://bsd.lv \(dqThe BSD.lv Project\(dq .Dl \&.Lk http://bsd.lv .Pp See also @@ -2115,7 +1887,7 @@ Synonym for Display a mathematical symbol. Its syntax is as follows: .Pp -.D1 Pf \. Sx \&Ms Cm symbol +.D1 Pf \. Sx \&Ms Ar symbol .Pp Examples: .Dl \&.Ms sigma @@ -2126,7 +1898,7 @@ Format a hyperlink. Its syntax is as follows: .Pp -.D1 Pf \. Sx \&Mt Cm address +.D1 Pf \. Sx \&Mt Ar address .Pp Examples: .Dl \&.Mt discuss@manpages.bsd.lv @@ -2139,8 +1911,8 @@ section subsequent the macro. .Pp Examples: -.Dl \&.Sx \&Nd mdoc language reference -.Dl \&.Sx \&Nd format and display UNIX manuals +.Dl Pf . Sx \&Nd mdoc language reference +.Dl Pf . Sx \&Nd format and display UNIX manuals .Pp The .Sx \&Nd @@ -2192,19 +1964,44 @@ macro rather than .Sx \&Nm to mark up the name of the manual page. .Ss \&No -A -.Dq noop -macro used to terminate prior macro contexts. +Normal text. +Closes the scope of any preceding in-line macro. +When used after physical formatting macros like +.Sx \&Em +or +.Sx \&Sy , +switches back to the standard font face and weight. +Can also be used to embed plain text strings in macro lines +using semantic annotation macros. .Pp Examples: -.Dl \&.Sx \&Fl ab \&No cd \&Fl ef +.Dl ".Em italic , Sy bold , No and roman" +.Pp +.Bd -literal -offset indent -compact +\&.Sm off +\&.Cm :C No / Ar pattern No / Ar replacement No / +\&.Sm on +.Ed +.Pp +See also +.Sx \&Em , +.Sx \&Li , +and +.Sx \&Sy . .Ss \&Ns -Suppress a space. -Following invocation, text is interpreted as free-form text until a -macro is encountered. +Suppress a space between the output of the preceding macro +and the following text or macro. +Following invocation, input is interpreted as normal text +just like after an +.Sx \&No +macro. +.Pp +This has no effect when invoked at the start of a macro line. .Pp Examples: -.Dl \&.Fl o \&Ns \&Ar output +.Dl ".Ar name Ns = Ns Ar value" +.Dl ".Cm :M Ns Ar pattern" +.Dl ".Fl o Ns Ar output" .Pp See also .Sx \&No @@ -2244,9 +2041,11 @@ Examples: \&.Oc .Ed .Ss \&Op -Command-line option. -Used when listing options to command-line utilities. +Optional part of a command line. Prints the argument(s) in brackets. +This is most often used in the +.Em SYNOPSIS +section of section 1 and 8 manual pages. .Pp Examples: .Dl \&.Op \&Fl a \&Ar b @@ -2262,10 +2061,10 @@ any file. Its syntax is as follows: .Pp -.D1 Pf \. Sx \&Os Op Cm system Op Cm version +.D1 Pf \. Sx \&Os Op Ar system Op Ar version .Pp The optional -.Cm system +.Ar system parameter specifies the relevant operating system or environment. Left unspecified, it defaults to the local operating system version. This is the suggested form. @@ -2280,10 +2079,13 @@ See also and .Sx \&Dt . .Ss \&Ot -Unknown usage. +This macro is obsolete and not implemented in +.Xr mandoc 1 . .Pp -.Em Remarks : -this macro has been deprecated. +Historical +.Xr mdoc 7 +packages described it as +.Dq "old function type (FORTRAN)" . .Ss \&Ox Format the .Ox @@ -2304,9 +2106,9 @@ See also and .Sx \&Ux . .Ss \&Pa -A file-system path. -If an argument is not provided, the string -.Dq \(ti +An absolute or relative file system path, or a file or directory name. +If an argument is not provided, the character +.Sq \(ti is used as a default. .Pp Examples: @@ -2319,19 +2121,25 @@ See also Close parenthesised context opened by .Sx \&Po . .Ss \&Pf -Removes the space +Removes the space between its argument .Pq Dq prefix -between its arguments. +and the following macro. Its syntax is as follows: .Pp -.D1 Pf \. \&Pf Cm prefix suffix +.D1 .Pf Ar prefix macro arguments ... .Pp -The -.Cm suffix -argument may be a macro. +This is equivalent to: +.Pp +.D1 .No Ar prefix No \&Ns Ar macro arguments ... .Pp Examples: -.Dl \&.Pf \e. \&Sx \&Pf \&Cm prefix suffix +.Dl ".Pf $ Ar variable_name" +.Dl ".Pf 0x Ar hex_digits" +.Pp +See also +.Sx \&Ns +and +.Sx \&Sm . .Ss \&Po Multi-line version of .Sx \&Pq . @@ -2339,6 +2147,18 @@ Multi-line version of Break a paragraph. This will assert vertical space between prior and subsequent macros and/or text. +.Pp +Paragraph breaks are not needed before or after +.Sx \&Sh +or +.Sx \&Ss +macros or before displays +.Pq Sx \&Bd +or lists +.Pq Sx \&Bl +unless the +.Fl compact +flag is given. .Ss \&Pq Parenthesised enclosure. .Pp @@ -2358,7 +2178,7 @@ Multi-line version of .Sx \&Qq . .Ss \&Qq Encloses its arguments in -.Dq typewriter +.Qq typewriter double-quotes. Consider using .Sx \&Dq . @@ -2414,16 +2234,22 @@ block is used within a SEE ALSO section, a vertical space is asserted before the rendered output, else the block continues on the current line. .Ss \&Rv -Inserts text regarding a function call's return value. -This macro must consist of the -.Fl std -argument followed by an optional -.Ar function . +Insert a standard sentence regarding a function call's return value of 0 +on success and \-1 on error, with the +.Va errno +libc global variable set on error. +Its syntax is as follows: +.Pp +.D1 Pf \. Sx \&Rv Fl std Op Ar function ... +.Pp If .Ar function -is not provided, the document's name as stipulated by the first +is not specified, the document's name set by .Sx \&Nm -is provided. +is used. +Multiple +.Ar function +arguments are treated as separate functions. .Pp See also .Sx \&Ex . @@ -2439,6 +2265,9 @@ custom sections be used. .Pp Section names should be unique so that they may be keyed by .Sx \&Sx . +Although this macro is parsed, it should not consist of child node or it +may not be linked with +.Sx \&Sx . .Pp See also .Sx \&Pp , @@ -2456,14 +2285,14 @@ By default, spacing is When switched .Cm off , no white space is inserted between macro arguments and between the -output generated from adjacent macros, but free-form text lines +output generated from adjacent macros, but text lines still get normal spacing between words and sentences. .Ss \&So Multi-line version of .Sx \&Sq . .Ss \&Sq Encloses its arguments in -.Dq typewriter +.Sq typewriter single-quotes. .Pp See also @@ -2472,16 +2301,21 @@ See also and .Sx \&So . .Ss \&Ss -Begin a new sub-section. +Begin a new subsection. Unlike with .Sx \&Sh , -there's no convention for sub-sections. -Conventional sections, as described in -.Sx MANUAL STRUCTURE , -rarely have sub-sections. +there is no convention for the naming of subsections. +Except +.Em DESCRIPTION , +the conventional sections described in +.Sx MANUAL STRUCTURE +rarely have subsections. .Pp Sub-section names should be unique so that they may be keyed by .Sx \&Sx . +Although this macro is parsed, it should not consist of child node or it +may not be linked with +.Sx \&Sx . .Pp See also .Sx \&Pp , @@ -2539,6 +2373,8 @@ The following standards are recognised: .St -isoC-tcor2 .It \-isoC-99 .St -isoC-99 +.It \-isoC-2011 +.St -isoC-2011 .It \-iso9945-1-90 .St -iso9945-1-90 .It \-iso9945-1-96 @@ -2555,6 +2391,8 @@ The following standards are recognised: .St -ieee754 .It \-iso8802-3 .St -iso8802-3 +.It \-iso8601 +.St -iso8601 .It \-ieee1275-94 .St -ieee1275-94 .It \-xpg3 @@ -2563,6 +2401,7 @@ The following standards are recognised: .St -xpg4 .It \-xpg4.2 .St -xpg4.2 +.It \-xpg4.3 .St -xpg4.3 .It \-xbd5 .St -xbd5 @@ -2586,8 +2425,8 @@ The following standards are recognised: .St -svid4 .El .Ss \&Sx -Reference a section or sub-section. -The referenced section or sub-section name must be identical to the +Reference a section or subsection in the same manual page. +The referenced section or subsection name must be identical to the enclosed argument, including whitespace. .Pp Examples: @@ -2605,17 +2444,28 @@ stylistically decorating technical terms. .Pp See also .Sx \&Bf , +.Sx \&Em , .Sx \&Li , and -.Sx \&Em . +.Sx \&No . +.Ss \&Ta +Table cell separator in +.Sx \&Bl Fl column +lists; can only be used below +.Sx \&It . .Ss \&Tn Format a tradename. .Pp +Since this macro is often implemented to use a small caps font, +it has historically been used for acronyms (like ASCII) as well. +Such usage is not recommended because it would use the same macro +sometimes for semantical annotation, sometimes for physical formatting. +.Pp Examples: .Dl \&.Tn IBM .Ss \&Ud Prints out -.Dq currently under development . +.Dq currently under development. .Ss \&Ux Format the UNIX name. Accepts no argument. @@ -2645,11 +2495,14 @@ This is also used for indicating global variables in the section, in which case a variable name is also specified. Note that it accepts .Sx Block partial-implicit -syntax when invoked as the first macro in the +syntax when invoked as the first macro on an input line in the .Em SYNOPSIS section, else it accepts ordinary .Sx In-line syntax. +In the former case, this macro starts a new output line, +and a blank line is inserted in front if there is a preceding +function definition or include directive. .Pp Note that this should not be confused with .Sx \&Ft , @@ -2679,15 +2532,15 @@ Link to another manual .Pq Qq cross-reference . Its syntax is as follows: .Pp -.D1 Pf \. Sx \&Xr Cm name section +.D1 Pf \. Sx \&Xr Ar name section .Pp The -.Cm name +.Ar name and -.Cm section +.Ar section are the name and section of the linked manual. If -.Cm section +.Ar section is followed by non-punctuation, an .Sx \&Ns is inserted into the token stream. @@ -2712,15 +2565,404 @@ This macro should not be used; it is implemented for compatibility with historical manuals. Its syntax is as follows: .Pp -.D1 Pf \. Sx \&sp Op Cm height +.D1 Pf \. Sx \&sp Op Ar height .Pp The -.Cm height +.Ar height argument must be formatted as described in .Sx Scaling Widths . If unspecified, .Sx \&sp asserts a single vertical space. +.Sh MACRO SYNTAX +The syntax of a macro depends on its classification. +In this section, +.Sq \-arg +refers to macro arguments, which may be followed by zero or more +.Sq parm +parameters; +.Sq \&Yo +opens the scope of a macro; and if specified, +.Sq \&Yc +closes it out. +.Pp +The +.Em Callable +column indicates that the macro may also be called by passing its name +as an argument to another macro. +For example, +.Sq \&.Op \&Fl O \&Ar file +produces +.Sq Op Fl O Ar file . +To prevent a macro call and render the macro name literally, +escape it by prepending a zero-width space, +.Sq \e& . +For example, +.Sq \&Op \e&Fl O +produces +.Sq Op \&Fl O . +If a macro is not callable but its name appears as an argument +to another macro, it is interpreted as opaque text. +For example, +.Sq \&.Fl \&Sh +produces +.Sq Fl \&Sh . +.Pp +The +.Em Parsed +column indicates whether the macro may call other macros by receiving +their names as arguments. +If a macro is not parsed but the name of another macro appears +as an argument, it is interpreted as opaque text. +.Pp +The +.Em Scope +column, if applicable, describes closure rules. +.Ss Block full-explicit +Multi-line scope closed by an explicit closing macro. +All macros contains bodies; only +.Sx \&Bf +and +.Pq optionally +.Sx \&Bl +contain a head. +.Bd -literal -offset indent +\&.Yo \(lB\-arg \(lBparm...\(rB\(rB \(lBhead...\(rB +\(lBbody...\(rB +\&.Yc +.Ed +.Bl -column "MacroX" "CallableX" "ParsedX" "closed by XXX" -offset indent +.It Em Macro Ta Em Callable Ta Em Parsed Ta Em Scope +.It Sx \&Bd Ta \&No Ta \&No Ta closed by Sx \&Ed +.It Sx \&Bf Ta \&No Ta \&No Ta closed by Sx \&Ef +.It Sx \&Bk Ta \&No Ta \&No Ta closed by Sx \&Ek +.It Sx \&Bl Ta \&No Ta \&No Ta closed by Sx \&El +.It Sx \&Ed Ta \&No Ta \&No Ta opened by Sx \&Bd +.It Sx \&Ef Ta \&No Ta \&No Ta opened by Sx \&Bf +.It Sx \&Ek Ta \&No Ta \&No Ta opened by Sx \&Bk +.It Sx \&El Ta \&No Ta \&No Ta opened by Sx \&Bl +.El +.Ss Block full-implicit +Multi-line scope closed by end-of-file or implicitly by another macro. +All macros have bodies; some +.Po +.Sx \&It Fl bullet , +.Fl hyphen , +.Fl dash , +.Fl enum , +.Fl item +.Pc +don't have heads; only one +.Po +.Sx \&It +in +.Sx \&Bl Fl column +.Pc +has multiple heads. +.Bd -literal -offset indent +\&.Yo \(lB\-arg \(lBparm...\(rB\(rB \(lBhead... \(lBTa head...\(rB\(rB +\(lBbody...\(rB +.Ed +.Bl -column "MacroX" "CallableX" "ParsedX" "closed by XXXXXXXXXXX" -offset indent +.It Em Macro Ta Em Callable Ta Em Parsed Ta Em Scope +.It Sx \&It Ta \&No Ta Yes Ta closed by Sx \&It , Sx \&El +.It Sx \&Nd Ta \&No Ta \&No Ta closed by Sx \&Sh +.It Sx \&Nm Ta \&No Ta Yes Ta closed by Sx \&Nm , Sx \&Sh , Sx \&Ss +.It Sx \&Sh Ta \&No Ta Yes Ta closed by Sx \&Sh +.It Sx \&Ss Ta \&No Ta Yes Ta closed by Sx \&Sh , Sx \&Ss +.El +.Pp +Note that the +.Sx \&Nm +macro is a +.Sx Block full-implicit +macro only when invoked as the first macro +in a +.Em SYNOPSIS +section line, else it is +.Sx In-line . +.Ss Block partial-explicit +Like block full-explicit, but also with single-line scope. +Each has at least a body and, in limited circumstances, a head +.Po +.Sx \&Fo , +.Sx \&Eo +.Pc +and/or tail +.Pq Sx \&Ec . +.Bd -literal -offset indent +\&.Yo \(lB\-arg \(lBparm...\(rB\(rB \(lBhead...\(rB +\(lBbody...\(rB +\&.Yc \(lBtail...\(rB + +\&.Yo \(lB\-arg \(lBparm...\(rB\(rB \(lBhead...\(rB \ +\(lBbody...\(rB \&Yc \(lBtail...\(rB +.Ed +.Bl -column "MacroX" "CallableX" "ParsedX" "closed by XXXX" -offset indent +.It Em Macro Ta Em Callable Ta Em Parsed Ta Em Scope +.It Sx \&Ac Ta Yes Ta Yes Ta opened by Sx \&Ao +.It Sx \&Ao Ta Yes Ta Yes Ta closed by Sx \&Ac +.It Sx \&Bc Ta Yes Ta Yes Ta closed by Sx \&Bo +.It Sx \&Bo Ta Yes Ta Yes Ta opened by Sx \&Bc +.It Sx \&Brc Ta Yes Ta Yes Ta opened by Sx \&Bro +.It Sx \&Bro Ta Yes Ta Yes Ta closed by Sx \&Brc +.It Sx \&Dc Ta Yes Ta Yes Ta opened by Sx \&Do +.It Sx \&Do Ta Yes Ta Yes Ta closed by Sx \&Dc +.It Sx \&Ec Ta Yes Ta Yes Ta opened by Sx \&Eo +.It Sx \&Eo Ta Yes Ta Yes Ta closed by Sx \&Ec +.It Sx \&Fc Ta Yes Ta Yes Ta opened by Sx \&Fo +.It Sx \&Fo Ta \&No Ta \&No Ta closed by Sx \&Fc +.It Sx \&Oc Ta Yes Ta Yes Ta closed by Sx \&Oo +.It Sx \&Oo Ta Yes Ta Yes Ta opened by Sx \&Oc +.It Sx \&Pc Ta Yes Ta Yes Ta closed by Sx \&Po +.It Sx \&Po Ta Yes Ta Yes Ta opened by Sx \&Pc +.It Sx \&Qc Ta Yes Ta Yes Ta opened by Sx \&Oo +.It Sx \&Qo Ta Yes Ta Yes Ta closed by Sx \&Oc +.It Sx \&Re Ta \&No Ta \&No Ta opened by Sx \&Rs +.It Sx \&Rs Ta \&No Ta \&No Ta closed by Sx \&Re +.It Sx \&Sc Ta Yes Ta Yes Ta opened by Sx \&So +.It Sx \&So Ta Yes Ta Yes Ta closed by Sx \&Sc +.It Sx \&Xc Ta Yes Ta Yes Ta opened by Sx \&Xo +.It Sx \&Xo Ta Yes Ta Yes Ta closed by Sx \&Xc +.El +.Ss Block partial-implicit +Like block full-implicit, but with single-line scope closed by the +end of the line. +.Bd -literal -offset indent +\&.Yo \(lB\-arg \(lBval...\(rB\(rB \(lBbody...\(rB \(lBres...\(rB +.Ed +.Bl -column "MacroX" "CallableX" "ParsedX" -offset indent +.It Em Macro Ta Em Callable Ta Em Parsed +.It Sx \&Aq Ta Yes Ta Yes +.It Sx \&Bq Ta Yes Ta Yes +.It Sx \&Brq Ta Yes Ta Yes +.It Sx \&D1 Ta \&No Ta \&Yes +.It Sx \&Dl Ta \&No Ta Yes +.It Sx \&Dq Ta Yes Ta Yes +.It Sx \&Op Ta Yes Ta Yes +.It Sx \&Pq Ta Yes Ta Yes +.It Sx \&Ql Ta Yes Ta Yes +.It Sx \&Qq Ta Yes Ta Yes +.It Sx \&Sq Ta Yes Ta Yes +.It Sx \&Vt Ta Yes Ta Yes +.El +.Pp +Note that the +.Sx \&Vt +macro is a +.Sx Block partial-implicit +only when invoked as the first macro +in a +.Em SYNOPSIS +section line, else it is +.Sx In-line . +.Ss Special block macro +The +.Sx \&Ta +macro can only be used below +.Sx \&It +in +.Sx \&Bl Fl column +lists. +It delimits blocks representing table cells; +these blocks have bodies, but no heads. +.Bl -column "MacroX" "CallableX" "ParsedX" "closed by XXXX" -offset indent +.It Em Macro Ta Em Callable Ta Em Parsed Ta Em Scope +.It Sx \&Ta Ta Yes Ta Yes Ta closed by Sx \&Ta , Sx \&It +.El +.Ss In-line +Closed by the end of the line, fixed argument lengths, +and/or subsequent macros. +In-line macros have only text children. +If a number (or inequality) of arguments is +.Pq n , +then the macro accepts an arbitrary number of arguments. +.Bd -literal -offset indent +\&.Yo \(lB\-arg \(lBval...\(rB\(rB \(lBargs...\(rB \(lBres...\(rB + +\&.Yo \(lB\-arg \(lBval...\(rB\(rB \(lBargs...\(rB Yc... + +\&.Yo \(lB\-arg \(lBval...\(rB\(rB arg0 arg1 argN +.Ed +.Bl -column "MacroX" "CallableX" "ParsedX" "Arguments" -offset indent +.It Em Macro Ta Em Callable Ta Em Parsed Ta Em Arguments +.It Sx \&%A Ta \&No Ta \&No Ta >0 +.It Sx \&%B Ta \&No Ta \&No Ta >0 +.It Sx \&%C Ta \&No Ta \&No Ta >0 +.It Sx \&%D Ta \&No Ta \&No Ta >0 +.It Sx \&%I Ta \&No Ta \&No Ta >0 +.It Sx \&%J Ta \&No Ta \&No Ta >0 +.It Sx \&%N Ta \&No Ta \&No Ta >0 +.It Sx \&%O Ta \&No Ta \&No Ta >0 +.It Sx \&%P Ta \&No Ta \&No Ta >0 +.It Sx \&%Q Ta \&No Ta \&No Ta >0 +.It Sx \&%R Ta \&No Ta \&No Ta >0 +.It Sx \&%T Ta \&No Ta \&No Ta >0 +.It Sx \&%U Ta \&No Ta \&No Ta >0 +.It Sx \&%V Ta \&No Ta \&No Ta >0 +.It Sx \&Ad Ta Yes Ta Yes Ta >0 +.It Sx \&An Ta Yes Ta Yes Ta >0 +.It Sx \&Ap Ta Yes Ta Yes Ta 0 +.It Sx \&Ar Ta Yes Ta Yes Ta n +.It Sx \&At Ta Yes Ta Yes Ta 1 +.It Sx \&Bsx Ta Yes Ta Yes Ta n +.It Sx \&Bt Ta \&No Ta \&No Ta 0 +.It Sx \&Bx Ta Yes Ta Yes Ta n +.It Sx \&Cd Ta Yes Ta Yes Ta >0 +.It Sx \&Cm Ta Yes Ta Yes Ta >0 +.It Sx \&Db Ta \&No Ta \&No Ta 1 +.It Sx \&Dd Ta \&No Ta \&No Ta n +.It Sx \&Dt Ta \&No Ta \&No Ta n +.It Sx \&Dv Ta Yes Ta Yes Ta >0 +.It Sx \&Dx Ta Yes Ta Yes Ta n +.It Sx \&Em Ta Yes Ta Yes Ta >0 +.It Sx \&En Ta \&No Ta \&No Ta 0 +.It Sx \&Er Ta Yes Ta Yes Ta >0 +.It Sx \&Es Ta \&No Ta \&No Ta 0 +.It Sx \&Ev Ta Yes Ta Yes Ta >0 +.It Sx \&Ex Ta \&No Ta \&No Ta n +.It Sx \&Fa Ta Yes Ta Yes Ta >0 +.It Sx \&Fd Ta \&No Ta \&No Ta >0 +.It Sx \&Fl Ta Yes Ta Yes Ta n +.It Sx \&Fn Ta Yes Ta Yes Ta >0 +.It Sx \&Fr Ta \&No Ta \&No Ta n +.It Sx \&Ft Ta Yes Ta Yes Ta >0 +.It Sx \&Fx Ta Yes Ta Yes Ta n +.It Sx \&Hf Ta \&No Ta \&No Ta n +.It Sx \&Ic Ta Yes Ta Yes Ta >0 +.It Sx \&In Ta \&No Ta \&No Ta 1 +.It Sx \&Lb Ta \&No Ta \&No Ta 1 +.It Sx \&Li Ta Yes Ta Yes Ta >0 +.It Sx \&Lk Ta Yes Ta Yes Ta >0 +.It Sx \&Lp Ta \&No Ta \&No Ta 0 +.It Sx \&Ms Ta Yes Ta Yes Ta >0 +.It Sx \&Mt Ta Yes Ta Yes Ta >0 +.It Sx \&Nm Ta Yes Ta Yes Ta n +.It Sx \&No Ta Yes Ta Yes Ta 0 +.It Sx \&Ns Ta Yes Ta Yes Ta 0 +.It Sx \&Nx Ta Yes Ta Yes Ta n +.It Sx \&Os Ta \&No Ta \&No Ta n +.It Sx \&Ot Ta \&No Ta \&No Ta n +.It Sx \&Ox Ta Yes Ta Yes Ta n +.It Sx \&Pa Ta Yes Ta Yes Ta n +.It Sx \&Pf Ta Yes Ta Yes Ta 1 +.It Sx \&Pp Ta \&No Ta \&No Ta 0 +.It Sx \&Rv Ta \&No Ta \&No Ta n +.It Sx \&Sm Ta \&No Ta \&No Ta 1 +.It Sx \&St Ta \&No Ta Yes Ta 1 +.It Sx \&Sx Ta Yes Ta Yes Ta >0 +.It Sx \&Sy Ta Yes Ta Yes Ta >0 +.It Sx \&Tn Ta Yes Ta Yes Ta >0 +.It Sx \&Ud Ta \&No Ta \&No Ta 0 +.It Sx \&Ux Ta Yes Ta Yes Ta n +.It Sx \&Va Ta Yes Ta Yes Ta n +.It Sx \&Vt Ta Yes Ta Yes Ta >0 +.It Sx \&Xr Ta Yes Ta Yes Ta >0 +.It Sx \&br Ta \&No Ta \&No Ta 0 +.It Sx \&sp Ta \&No Ta \&No Ta 1 +.El +.Ss Delimiters +When a macro argument consists of one single input character +considered as a delimiter, the argument gets special handling. +This does not apply when delimiters appear in arguments containing +more than one character. +Consequently, to prevent special handling and just handle it +like any other argument, a delimiter can be escaped by prepending +a zero-width space +.Pq Sq \e& . +In text lines, delimiters never need escaping, but may be used +as normal punctuation. +.Pp +For many macros, when the leading arguments are opening delimiters, +these delimiters are put before the macro scope, +and when the trailing arguments are closing delimiters, +these delimiters are put after the macro scope. +For example, +.Pp +.D1 Pf \. \&Aq "( [ word ] ) ." +.Pp +renders as: +.Pp +.D1 Aq ( [ word ] ) . +.Pp +Opening delimiters are: +.Pp +.Bl -tag -width Ds -offset indent -compact +.It \&( +left parenthesis +.It \&[ +left bracket +.El +.Pp +Closing delimiters are: +.Pp +.Bl -tag -width Ds -offset indent -compact +.It \&. +period +.It \&, +comma +.It \&: +colon +.It \&; +semicolon +.It \&) +right parenthesis +.It \&] +right bracket +.It \&? +question mark +.It \&! +exclamation mark +.El +.Pp +Note that even a period preceded by a backslash +.Pq Sq \e.\& +gets this special handling; use +.Sq \e&. +to prevent that. +.Pp +Many in-line macros interrupt their scope when they encounter +delimiters, and resume their scope when more arguments follow that +are not delimiters. +For example, +.Pp +.D1 Pf \. \&Fl "a ( b | c \e*(Ba d ) e" +.Pp +renders as: +.Pp +.D1 Fl a ( b | c \*(Ba d ) e +.Pp +This applies to both opening and closing delimiters, +and also to the middle delimiter: +.Pp +.Bl -tag -width Ds -offset indent -compact +.It \&| +vertical bar +.El +.Pp +As a special case, the predefined string \e*(Ba is handled and rendered +in the same way as a plain +.Sq \&| +character. +Using this predefined string is not recommended in new manuals. +.Ss Font handling +In +.Nm +documents, usage of semantic markup is recommended in order to have +proper fonts automatically selected; only when no fitting semantic markup +is available, consider falling back to +.Sx Physical markup +macros. +Whenever any +.Nm +macro switches the +.Xr roff 7 +font mode, it will automatically restore the previous font when exiting +its scope. +Manually switching the font using the +.Xr roff 7 +.Ql \ef +font escape sequences is never required. .Sh COMPATIBILITY This section documents compatibility between mandoc and other other troff implementations, at this time limited to GNU troff @@ -2757,8 +2999,8 @@ Newer groff and mandoc print .Qq AT&T UNIX and the arguments. .It -.Sx \&Bd Fl column -does not recognize trailing punctuation characters when they immediately +.Sx \&Bl Fl column +does not recognise trailing punctuation characters when they immediately precede tabulator characters, but treats them as normal text and outputs a space before them. .It @@ -2767,9 +3009,12 @@ does not start a new line. \*[hist] .It .Sx \&Dd -without an argument prints -.Dq Epoch . -In mandoc, it resolves to the current date. +with non-standard arguments behaves very strangely. +When there are three arguments, they are printed verbatim. +Any other number of arguments is replaced by the current date, +but without any arguments the string +.Dq Epoch +is printed. .It .Sx \&Fl does not print a dash for an empty argument. @@ -2814,7 +3059,7 @@ In new groff and mandoc, any list may be nested by default and lists will restart the sequence only for the sub-list. .It .Sx \&Li -followed by a reserved character is incorrectly used in some manuals +followed by a delimiter is incorrectly used in some manuals instead of properly quoting that character, which sometimes works with historic groff. .It @@ -2867,7 +3112,7 @@ The following features are unimplemented in mandoc: .Fl offset Ar center and .Fl offset Ar right . -Groff does not implement centered and flush-right rendering either, +Groff does not implement centred and flush-right rendering either, but produces large indentations. .It The @@ -2903,8 +3148,9 @@ This is not supported by mandoc. .Sh SEE ALSO .Xr man 1 , .Xr mandoc 1 , +.Xr eqn 7 , .Xr man 7 , -.Xr mandoc_char 7 +.Xr mandoc_char 7 , .Xr roff 7 , .Xr tbl 7 .Sh HISTORY @@ -2922,4 +3168,5 @@ utility written by Kristaps Dzonsons appeared in The .Nm reference was written by -.An Kristaps Dzonsons Aq kristaps@bsd.lv . +.An Kristaps Dzonsons , +.Mt kristaps@bsd.lv . diff --git a/external/bsd/mdocml/dist/mdoc.c b/external/bsd/mdocml/dist/mdoc.c index b6216b5f0..b44a41b82 100644 --- a/external/bsd/mdocml/dist/mdoc.c +++ b/external/bsd/mdocml/dist/mdoc.c @@ -1,6 +1,6 @@ -/* $Vendor-Id: mdoc.c,v 1.177 2011/01/03 11:27:33 kristaps Exp $ */ +/* $Vendor-Id: mdoc.c,v 1.196 2011/09/30 00:13:28 schwarze Exp $ */ /* - * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any @@ -28,6 +28,7 @@ #include <string.h> #include <time.h> +#include "mdoc.h" #include "mandoc.h" #include "libmdoc.h" #include "libmandoc.h" @@ -96,11 +97,11 @@ static struct mdoc_node *node_alloc(struct mdoc *, int, int, enum mdoct, enum mdoc_type); static int node_append(struct mdoc *, struct mdoc_node *); +#if 0 +static int mdoc_preptext(struct mdoc *, int, char *, int); +#endif static int mdoc_ptext(struct mdoc *, int, char *, int); static int mdoc_pmacro(struct mdoc *, int, char *, int); -static int mdoc_span_alloc(struct mdoc *, - const struct tbl_span *); - const struct mdoc_node * mdoc_node(const struct mdoc *m) @@ -141,6 +142,8 @@ mdoc_free1(struct mdoc *mdoc) free(mdoc->meta.vol); if (mdoc->meta.msec) free(mdoc->meta.msec); + if (mdoc->meta.date) + free(mdoc->meta.date); } @@ -157,6 +160,7 @@ mdoc_alloc1(struct mdoc *mdoc) mdoc->last = mandoc_calloc(1, sizeof(struct mdoc_node)); mdoc->first = mdoc->last; mdoc->last->type = MDOC_ROOT; + mdoc->last->tok = MDOC_MAX; mdoc->next = MDOC_NEXT_CHILD; } @@ -193,15 +197,14 @@ mdoc_free(struct mdoc *mdoc) * Allocate volatile and non-volatile parse resources. */ struct mdoc * -mdoc_alloc(struct regset *regs, void *data, mandocmsg msg) +mdoc_alloc(struct roff *roff, struct mparse *parse) { struct mdoc *p; p = mandoc_calloc(1, sizeof(struct mdoc)); - p->msg = msg; - p->data = data; - p->regs = regs; + p->parse = parse; + p->roff = roff; mdoc_hash_init(); mdoc_alloc1(p); @@ -225,20 +228,51 @@ mdoc_endparse(struct mdoc *m) } int -mdoc_addspan(struct mdoc *m, const struct tbl_span *sp) +mdoc_addeqn(struct mdoc *m, const struct eqn *ep) { + struct mdoc_node *n; assert( ! (MDOC_HALT & m->flags)); /* No text before an initial macro. */ if (SEC_NONE == m->lastnamed) { - /* FIXME: grab from span. */ - mdoc_pmsg(m, 0, 0, MANDOCERR_NOTEXT); + mdoc_pmsg(m, ep->ln, ep->pos, MANDOCERR_NOTEXT); return(1); } - return(mdoc_span_alloc(m, sp)); + n = node_alloc(m, ep->ln, ep->pos, MDOC_MAX, MDOC_EQN); + n->eqn = ep; + + if ( ! node_append(m, n)) + return(0); + + m->next = MDOC_NEXT_SIBLING; + return(1); +} + +int +mdoc_addspan(struct mdoc *m, const struct tbl_span *sp) +{ + struct mdoc_node *n; + + assert( ! (MDOC_HALT & m->flags)); + + /* No text before an initial macro. */ + + if (SEC_NONE == m->lastnamed) { + mdoc_pmsg(m, sp->line, 0, MANDOCERR_NOTEXT); + return(1); + } + + n = node_alloc(m, sp->line, 0, MDOC_MAX, MDOC_TBL); + n->span = sp; + + if ( ! node_append(m, n)) + return(0); + + m->next = MDOC_NEXT_SIBLING; + return(1); } @@ -260,34 +294,18 @@ mdoc_parseln(struct mdoc *m, int ln, char *buf, int offs) * whether this mode is on or off. * Note that this mode is also switched by the Sh macro. */ - if (m->regs->regs[(int)REG_nS].set) { - if (m->regs->regs[(int)REG_nS].v.u) + if (roff_regisset(m->roff, REG_nS)) { + if (roff_regget(m->roff, REG_nS)) m->flags |= MDOC_SYNOPSIS; else m->flags &= ~MDOC_SYNOPSIS; } - return(('.' == buf[offs] || '\'' == buf[offs]) ? + return(mandoc_getcontrol(buf, &offs) ? mdoc_pmacro(m, ln, buf, offs) : mdoc_ptext(m, ln, buf, offs)); } - -int -mdoc_vmsg(struct mdoc *mdoc, enum mandocerr t, - int ln, int pos, const char *fmt, ...) -{ - char buf[256]; - va_list ap; - - va_start(ap, fmt); - vsnprintf(buf, sizeof(buf) - 1, fmt, ap); - va_end(ap); - - return((*mdoc->msg)(t, mdoc->data, ln, pos, buf)); -} - - int mdoc_macro(MACRO_PROT_ARGS) { @@ -314,8 +332,9 @@ mdoc_macro(MACRO_PROT_ARGS) m->meta.vol = mandoc_strdup("LOCAL"); if (NULL == m->meta.os) m->meta.os = mandoc_strdup("LOCAL"); - if (0 == m->meta.date) - m->meta.date = time(NULL); + if (NULL == m->meta.date) + m->meta.date = mandoc_normdate + (m->parse, NULL, line, ppos); m->flags |= MDOC_PBODY; } @@ -546,37 +565,13 @@ mdoc_elem_alloc(struct mdoc *m, int line, int pos, return(1); } -static int -mdoc_span_alloc(struct mdoc *m, const struct tbl_span *sp) -{ - struct mdoc_node *n; - - /* FIXME: grab from tbl_span. */ - n = node_alloc(m, 0, 0, MDOC_MAX, MDOC_TBL); - n->span = sp; - - if ( ! node_append(m, n)) - return(0); - - m->next = MDOC_NEXT_SIBLING; - return(1); -} - - int mdoc_word_alloc(struct mdoc *m, int line, int pos, const char *p) { struct mdoc_node *n; - size_t sv, len; - - len = strlen(p); n = node_alloc(m, line, pos, MDOC_MAX, MDOC_TEXT); - n->string = mandoc_malloc(len + 1); - sv = strlcpy(n->string, p, len + 1); - - /* Prohibit truncation. */ - assert(sv < len + 1); + n->string = roff_strdup(m->roff, p); if ( ! node_append(m, n)) return(0); @@ -652,6 +647,59 @@ mdoc_node_delete(struct mdoc *m, struct mdoc_node *p) mdoc_node_free(p); } +#if 0 +/* + * Pre-treat a text line. + * Text lines can consist of equations, which must be handled apart from + * the regular text. + * Thus, use this function to step through a line checking if it has any + * equations embedded in it. + * This must handle multiple equations AND equations that do not end at + * the end-of-line, i.e., will re-enter in the next roff parse. + */ +static int +mdoc_preptext(struct mdoc *m, int line, char *buf, int offs) +{ + char *start, *end; + char delim; + + while ('\0' != buf[offs]) { + /* Mark starting position if eqn is set. */ + start = NULL; + if ('\0' != (delim = roff_eqndelim(m->roff))) + if (NULL != (start = strchr(buf + offs, delim))) + *start++ = '\0'; + + /* Parse text as normal. */ + if ( ! mdoc_ptext(m, line, buf, offs)) + return(0); + + /* Continue only if an equation exists. */ + if (NULL == start) + break; + + /* Read past the end of the equation. */ + offs += start - (buf + offs); + assert(start == &buf[offs]); + if (NULL != (end = strchr(buf + offs, delim))) { + *end++ = '\0'; + while (' ' == *end) + end++; + } + + /* Parse the equation itself. */ + roff_openeqn(m->roff, NULL, line, offs, buf); + + /* Process a finished equation? */ + if (roff_closeeqn(m->roff)) + if ( ! mdoc_addeqn(m, roff_eqn(m->roff))) + return(0); + offs += (end - (buf + offs)); + } + + return(1); +} +#endif /* * Parse free-form text, that is, a line that does not begin with the @@ -663,15 +711,6 @@ mdoc_ptext(struct mdoc *m, int line, char *buf, int offs) char *c, *ws, *end; struct mdoc_node *n; - /* Ignore bogus comments. */ - - if ('\\' == buf[offs] && - '.' == buf[offs + 1] && - '"' == buf[offs + 2]) { - mdoc_pmsg(m, line, offs, MANDOCERR_BADCOMMENT); - return(1); - } - /* No text before an initial macro. */ if (SEC_NONE == m->lastnamed) { @@ -714,11 +753,6 @@ mdoc_ptext(struct mdoc *m, int line, char *buf, int offs) ws = NULL; for (c = end = buf + offs; *c; c++) { switch (*c) { - case '-': - if (mandoc_hyph(buf + offs, c)) - *c = ASCII_HYPH; - ws = NULL; - break; case ' ': if (NULL == ws) ws = c; @@ -798,64 +832,57 @@ static int mdoc_pmacro(struct mdoc *m, int ln, char *buf, int offs) { enum mdoct tok; - int i, j, sv; + int i, sv; char mac[5]; struct mdoc_node *n; - /* Empty lines are ignored. */ + /* Empty post-control lines are ignored. */ - offs++; - - if ('\0' == buf[offs]) + if ('"' == buf[offs]) { + mdoc_pmsg(m, ln, offs, MANDOCERR_BADCOMMENT); + return(1); + } else if ('\0' == buf[offs]) return(1); - i = offs; - - /* Accept tabs/whitespace after the initial control char. */ - - if (' ' == buf[i] || '\t' == buf[i]) { - i++; - while (buf[i] && (' ' == buf[i] || '\t' == buf[i])) - i++; - if ('\0' == buf[i]) - return(1); - } - - sv = i; + sv = offs; /* * Copy the first word into a nil-terminated buffer. * Stop copying when a tab, space, or eoln is encountered. */ - j = 0; - while (j < 4 && '\0' != buf[i] && ' ' != buf[i] && '\t' != buf[i]) - mac[j++] = buf[i++]; - mac[j] = '\0'; + i = 0; + while (i < 4 && '\0' != buf[offs] && + ' ' != buf[offs] && '\t' != buf[offs]) + mac[i++] = buf[offs++]; + + mac[i] = '\0'; + + tok = (i > 1 || i < 4) ? mdoc_hash_find(mac) : MDOC_MAX; - tok = (j > 1 || j < 4) ? mdoc_hash_find(mac) : MDOC_MAX; if (MDOC_MAX == tok) { - mdoc_vmsg(m, MANDOCERR_MACRO, ln, sv, "%s", buf + sv - 1); + mandoc_vmsg(MANDOCERR_MACRO, m->parse, + ln, sv, "%s", buf + sv - 1); return(1); } /* Disregard the first trailing tab, if applicable. */ - if ('\t' == buf[i]) - i++; + if ('\t' == buf[offs]) + offs++; /* Jump to the next non-whitespace word. */ - while (buf[i] && ' ' == buf[i]) - i++; + while (buf[offs] && ' ' == buf[offs]) + offs++; /* * Trailing whitespace. Note that tabs are allowed to be passed * into the parser as "text", so we only warn about spaces here. */ - if ('\0' == buf[i] && ' ' == buf[i - 1]) - mdoc_pmsg(m, ln, i - 1, MANDOCERR_EOLNSPACE); + if ('\0' == buf[offs] && ' ' == buf[offs - 1]) + mdoc_pmsg(m, ln, offs - 1, MANDOCERR_EOLNSPACE); /* * If an initial macro or a list invocation, divert directly @@ -863,7 +890,7 @@ mdoc_pmacro(struct mdoc *m, int ln, char *buf, int offs) */ if (NULL == m->last || MDOC_It == tok || MDOC_El == tok) { - if ( ! mdoc_macro(m, tok, ln, sv, &i, buf)) + if ( ! mdoc_macro(m, tok, ln, sv, &offs, buf)) goto err; return(1); } @@ -902,7 +929,7 @@ mdoc_pmacro(struct mdoc *m, int ln, char *buf, int offs) /* Normal processing of a macro. */ - if ( ! mdoc_macro(m, tok, ln, sv, &i, buf)) + if ( ! mdoc_macro(m, tok, ln, sv, &offs, buf)) goto err; return(1); @@ -913,4 +940,48 @@ err: /* Error out. */ return(0); } +enum mdelim +mdoc_isdelim(const char *p) +{ + if ('\0' == p[0]) + return(DELIM_NONE); + + if ('\0' == p[1]) + switch (p[0]) { + case('('): + /* FALLTHROUGH */ + case('['): + return(DELIM_OPEN); + case('|'): + return(DELIM_MIDDLE); + case('.'): + /* FALLTHROUGH */ + case(','): + /* FALLTHROUGH */ + case(';'): + /* FALLTHROUGH */ + case(':'): + /* FALLTHROUGH */ + case('?'): + /* FALLTHROUGH */ + case('!'): + /* FALLTHROUGH */ + case(')'): + /* FALLTHROUGH */ + case(']'): + return(DELIM_CLOSE); + default: + return(DELIM_NONE); + } + + if ('\\' != p[0]) + return(DELIM_NONE); + + if (0 == strcmp(p + 1, ".")) + return(DELIM_CLOSE); + if (0 == strcmp(p + 1, "*(Ba")) + return(DELIM_MIDDLE); + + return(DELIM_NONE); +} diff --git a/external/bsd/mdocml/dist/mdoc.h b/external/bsd/mdocml/dist/mdoc.h index 7ecc6a525..3aca4535c 100644 --- a/external/bsd/mdocml/dist/mdoc.h +++ b/external/bsd/mdocml/dist/mdoc.h @@ -1,6 +1,6 @@ -/* $Vendor-Id: mdoc.h,v 1.114 2011/01/01 12:18:37 kristaps Exp $ */ +/* $Vendor-Id: mdoc.h,v 1.122 2011/03/22 14:05:45 kristaps Exp $ */ /* - * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -17,9 +17,6 @@ #ifndef MDOC_H #define MDOC_H -/* - * What follows is a list of ALL possible macros. - */ enum mdoct { MDOC_Ap = 0, MDOC_Dd, @@ -146,43 +143,37 @@ enum mdoct { MDOC_MAX }; -/* - * What follows is a list of ALL possible macro arguments. - */ enum mdocargt { - MDOC_Split, - MDOC_Nosplit, - MDOC_Ragged, - MDOC_Unfilled, - MDOC_Literal, - MDOC_File, - MDOC_Offset, - MDOC_Bullet, - MDOC_Dash, - MDOC_Hyphen, - MDOC_Item, - MDOC_Enum, - MDOC_Tag, - MDOC_Diag, - MDOC_Hang, - MDOC_Ohang, - MDOC_Inset, - MDOC_Column, - MDOC_Width, - MDOC_Compact, - MDOC_Std, - MDOC_Filled, - MDOC_Words, - MDOC_Emphasis, - MDOC_Symbolic, - MDOC_Nested, - MDOC_Centred, + MDOC_Split, /* -split */ + MDOC_Nosplit, /* -nospli */ + MDOC_Ragged, /* -ragged */ + MDOC_Unfilled, /* -unfilled */ + MDOC_Literal, /* -literal */ + MDOC_File, /* -file */ + MDOC_Offset, /* -offset */ + MDOC_Bullet, /* -bullet */ + MDOC_Dash, /* -dash */ + MDOC_Hyphen, /* -hyphen */ + MDOC_Item, /* -item */ + MDOC_Enum, /* -enum */ + MDOC_Tag, /* -tag */ + MDOC_Diag, /* -diag */ + MDOC_Hang, /* -hang */ + MDOC_Ohang, /* -ohang */ + MDOC_Inset, /* -inset */ + MDOC_Column, /* -column */ + MDOC_Width, /* -width */ + MDOC_Compact, /* -compact */ + MDOC_Std, /* -std */ + MDOC_Filled, /* -filled */ + MDOC_Words, /* -words */ + MDOC_Emphasis, /* -emphasis */ + MDOC_Symbolic, /* -symbolic */ + MDOC_Nested, /* -nested */ + MDOC_Centred, /* -centered */ MDOC_ARG_MAX }; -/* - * Type of a syntax node. - */ enum mdoc_type { MDOC_TEXT, MDOC_ELEM, @@ -191,47 +182,47 @@ enum mdoc_type { MDOC_BODY, MDOC_BLOCK, MDOC_TBL, + MDOC_EQN, MDOC_ROOT }; /* * Section (named/unnamed) of `Sh'. Note that these appear in the - * conventional order imposed by mdoc.7. + * conventional order imposed by mdoc.7. In the case of SEC_NONE, no + * section has been invoked (this shouldn't happen). SEC_CUSTOM refers + * to other sections. */ enum mdoc_sec { - SEC_NONE = 0, /* No section, yet. */ - SEC_NAME, - SEC_LIBRARY, - SEC_SYNOPSIS, - SEC_DESCRIPTION, - SEC_IMPLEMENTATION, - SEC_RETURN_VALUES, - SEC_ENVIRONMENT, - SEC_FILES, - SEC_EXIT_STATUS, - SEC_EXAMPLES, - SEC_DIAGNOSTICS, - SEC_COMPATIBILITY, - SEC_ERRORS, - SEC_SEE_ALSO, - SEC_STANDARDS, - SEC_HISTORY, - SEC_AUTHORS, - SEC_CAVEATS, - SEC_BUGS, - SEC_SECURITY, - SEC_CUSTOM, /* User-defined. */ + SEC_NONE = 0, + SEC_NAME, /* NAME */ + SEC_LIBRARY, /* LIBRARY */ + SEC_SYNOPSIS, /* SYNOPSIS */ + SEC_DESCRIPTION, /* DESCRIPTION */ + SEC_IMPLEMENTATION, /* IMPLEMENTATION NOTES */ + SEC_RETURN_VALUES, /* RETURN VALUES */ + SEC_ENVIRONMENT, /* ENVIRONMENT */ + SEC_FILES, /* FILES */ + SEC_EXIT_STATUS, /* EXIT STATUS */ + SEC_EXAMPLES, /* EXAMPLES */ + SEC_DIAGNOSTICS, /* DIAGNOSTICS */ + SEC_COMPATIBILITY, /* COMPATIBILITY */ + SEC_ERRORS, /* ERRORS */ + SEC_SEE_ALSO, /* SEE ALSO */ + SEC_STANDARDS, /* STANDARDS */ + SEC_HISTORY, /* HISTORY */ + SEC_AUTHORS, /* AUTHORS */ + SEC_CAVEATS, /* CAVEATS */ + SEC_BUGS, /* BUGS */ + SEC_SECURITY, /* SECURITY */ + SEC_CUSTOM, SEC__MAX }; -/* - * Information from prologue. - */ struct mdoc_meta { char *msec; /* `Dt' section (1, 3p, etc.) */ char *vol; /* `Dt' volume (implied) */ char *arch; /* `Dt' arch (i386, etc.) */ - time_t date; /* `Dd' normalised date */ + char *date; /* `Dd' normalised date */ char *title; /* `Dt' title (FOO, etc.) */ char *os; /* `Os' system (OpenBSD, etc.) */ char *name; /* leading `Nm' name */ @@ -269,68 +260,50 @@ enum mdoc_endbody { ENDBODY_NOSPACE /* is broken: don't append a space */ }; -/* - * Normalised `Bl' list type. - */ enum mdoc_list { LIST__NONE = 0, - LIST_bullet, - LIST_column, - LIST_dash, - LIST_diag, - LIST_enum, - LIST_hang, - LIST_hyphen, - LIST_inset, - LIST_item, - LIST_ohang, - LIST_tag, + LIST_bullet, /* -bullet */ + LIST_column, /* -column */ + LIST_dash, /* -dash */ + LIST_diag, /* -diag */ + LIST_enum, /* -enum */ + LIST_hang, /* -hang */ + LIST_hyphen, /* -hyphen */ + LIST_inset, /* -inset */ + LIST_item, /* -item */ + LIST_ohang, /* -ohang */ + LIST_tag, /* -tag */ LIST_MAX }; -/* - * Normalised `Bd' display type. - */ enum mdoc_disp { DISP__NONE = 0, - DISP_centred, - DISP_ragged, - DISP_unfilled, - DISP_filled, - DISP_literal + DISP_centred, /* -centered */ + DISP_ragged, /* -ragged */ + DISP_unfilled, /* -unfilled */ + DISP_filled, /* -filled */ + DISP_literal /* -literal */ }; -/* - * Normalised `An' splitting argument. - */ enum mdoc_auth { AUTH__NONE = 0, - AUTH_split, - AUTH_nosplit + AUTH_split, /* -split */ + AUTH_nosplit /* -nosplit */ }; -/* - * Normalised `Bf' font type. - */ enum mdoc_font { FONT__NONE = 0, - FONT_Em, - FONT_Li, - FONT_Sy + FONT_Em, /* Em, -emphasis */ + FONT_Li, /* Li, -literal */ + FONT_Sy /* Sy, -symbolic */ }; -/* - * Normalised arguments for `Bd'. - */ struct mdoc_bd { const char *offs; /* -offset */ enum mdoc_disp type; /* -ragged, etc. */ int comp; /* -compact */ }; -/* - * Normalised arguments for `Bl'. - */ struct mdoc_bl { const char *width; /* -width */ const char *offs; /* -offset */ @@ -340,22 +313,16 @@ struct mdoc_bl { const char **cols; /* -column val ptr */ }; -/* - * Normalised arguments for `Bf'. - */ struct mdoc_bf { enum mdoc_font font; /* font */ }; -/* - * Normalised arguments for `An'. - */ struct mdoc_an { enum mdoc_auth auth; /* -split, etc. */ }; struct mdoc_rs { - struct mdoc_node *child_J; /* pointer to %J */ + int quote_T; /* whether to quote %T */ }; /* @@ -390,6 +357,8 @@ struct mdoc_node { #define MDOC_LINE (1 << 3) /* first macro/text on line */ #define MDOC_SYNPRETTY (1 << 4) /* SYNOPSIS-style formatting */ #define MDOC_ENDED (1 << 5) /* rendering has been ended */ +#define MDOC_DELIMO (1 << 6) +#define MDOC_DELIMC (1 << 7) enum mdoc_type type; /* AST node type */ enum mdoc_sec sec; /* current named section */ union mdoc_data *norm; /* normalised args */ @@ -401,35 +370,22 @@ struct mdoc_node { struct mdoc_node *tail; /* BLOCK */ char *string; /* TEXT */ const struct tbl_span *span; /* TBL */ + const struct eqn *eqn; /* EQN */ enum mdoc_endbody end; /* BODY */ }; -/* - * Names of macros. Index is enum mdoct. Indexing into this returns - * the normalised name, e.g., mdoc_macronames[MDOC_Sh] -> "Sh". - */ +/* Names of macros. Index is enum mdoct. */ extern const char *const *mdoc_macronames; -/* - * Names of macro args. Index is enum mdocargt. Indexing into this - * returns the normalised name, e.g., mdoc_argnames[MDOC_File] -> - * "file". - */ +/* Names of macro args. Index is enum mdocargt. */ extern const char *const *mdoc_argnames; __BEGIN_DECLS struct mdoc; -void mdoc_free(struct mdoc *); -struct mdoc *mdoc_alloc(struct regset *, void *, mandocmsg); -void mdoc_reset(struct mdoc *); -int mdoc_parseln(struct mdoc *, int, char *, int); const struct mdoc_node *mdoc_node(const struct mdoc *); const struct mdoc_meta *mdoc_meta(const struct mdoc *); -int mdoc_endparse(struct mdoc *); -int mdoc_addspan(struct mdoc *, - const struct tbl_span *); __END_DECLS diff --git a/external/bsd/mdocml/dist/mdoc_argv.c b/external/bsd/mdocml/dist/mdoc_argv.c index d3098050f..ef26e0260 100644 --- a/external/bsd/mdocml/dist/mdoc_argv.c +++ b/external/bsd/mdocml/dist/mdoc_argv.c @@ -1,6 +1,6 @@ -/* $Vendor-Id: mdoc_argv.c,v 1.62 2010/12/24 14:00:40 kristaps Exp $ */ +/* $Vendor-Id: mdoc_argv.c,v 1.81 2011/09/18 14:14:15 schwarze Exp $ */ /* - * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -21,45 +21,48 @@ #include <sys/types.h> #include <assert.h> -#include <ctype.h> #include <stdlib.h> #include <stdio.h> #include <string.h> +#include "mdoc.h" #include "mandoc.h" #include "libmdoc.h" #include "libmandoc.h" -/* - * Routines to parse arguments of macros. Arguments follow the syntax - * of `-arg [val [valN...]]'. Arguments come in all types: quoted - * arguments, multiple arguments per value, no-value arguments, etc. - * - * There's no limit to the number or arguments that may be allocated. - */ +#define MULTI_STEP 5 /* pre-allocate argument values */ +#define DELIMSZ 6 /* max possible size of a delimiter */ -#define ARGV_NONE (1 << 0) -#define ARGV_SINGLE (1 << 1) -#define ARGV_MULTI (1 << 2) -#define ARGV_OPT_SINGLE (1 << 3) +enum argsflag { + ARGSFL_NONE = 0, + ARGSFL_DELIM, /* handle delimiters of [[::delim::][ ]+]+ */ + ARGSFL_TABSEP /* handle tab/`Ta' separated phrases */ +}; -#define MULTI_STEP 5 +enum argvflag { + ARGV_NONE, /* no args to flag (e.g., -split) */ + ARGV_SINGLE, /* one arg to flag (e.g., -file xxx) */ + ARGV_MULTI, /* multiple args (e.g., -column xxx yyy) */ + ARGV_OPT_SINGLE /* optional arg (e.g., -offset [xxx]) */ +}; -static enum mdocargt argv_a2arg(enum mdoct, const char *); +struct mdocarg { + enum argsflag flags; + const enum mdocargt *argvs; +}; + +static void argn_free(struct mdoc_arg *, int); static enum margserr args(struct mdoc *, int, int *, - char *, int, char **); -static int argv(struct mdoc *, int, - struct mdoc_argv *, int *, char *); -static int argv_single(struct mdoc *, int, + char *, enum argsflag, char **); +static int args_checkpunct(const char *, int); +static int argv_multi(struct mdoc *, int, struct mdoc_argv *, int *, char *); static int argv_opt_single(struct mdoc *, int, struct mdoc_argv *, int *, char *); -static int argv_multi(struct mdoc *, int, +static int argv_single(struct mdoc *, int, struct mdoc_argv *, int *, char *); -/* Per-argument flags. */ - -static int mdoc_argvflags[MDOC_ARG_MAX] = { +static const enum argvflag argvflags[MDOC_ARG_MAX] = { ARGV_NONE, /* MDOC_Split */ ARGV_NONE, /* MDOC_Nosplit */ ARGV_NONE, /* MDOC_Ragged */ @@ -88,129 +91,183 @@ static int mdoc_argvflags[MDOC_ARG_MAX] = { ARGV_NONE /* MDOC_Symbolic */ }; -static int mdoc_argflags[MDOC_MAX] = { - 0, /* Ap */ - 0, /* Dd */ - 0, /* Dt */ - 0, /* Os */ - 0, /* Sh */ - 0, /* Ss */ - 0, /* Pp */ - ARGS_DELIM, /* D1 */ - ARGS_DELIM, /* Dl */ - 0, /* Bd */ - 0, /* Ed */ - 0, /* Bl */ - 0, /* El */ - 0, /* It */ - ARGS_DELIM, /* Ad */ - ARGS_DELIM, /* An */ - ARGS_DELIM, /* Ar */ - 0, /* Cd */ - ARGS_DELIM, /* Cm */ - ARGS_DELIM, /* Dv */ - ARGS_DELIM, /* Er */ - ARGS_DELIM, /* Ev */ - 0, /* Ex */ - ARGS_DELIM, /* Fa */ - 0, /* Fd */ - ARGS_DELIM, /* Fl */ - ARGS_DELIM, /* Fn */ - ARGS_DELIM, /* Ft */ - ARGS_DELIM, /* Ic */ - 0, /* In */ - ARGS_DELIM, /* Li */ - 0, /* Nd */ - ARGS_DELIM, /* Nm */ - ARGS_DELIM, /* Op */ - 0, /* Ot */ - ARGS_DELIM, /* Pa */ - 0, /* Rv */ - ARGS_DELIM, /* St */ - ARGS_DELIM, /* Va */ - ARGS_DELIM, /* Vt */ - ARGS_DELIM, /* Xr */ - 0, /* %A */ - 0, /* %B */ - 0, /* %D */ - 0, /* %I */ - 0, /* %J */ - 0, /* %N */ - 0, /* %O */ - 0, /* %P */ - 0, /* %R */ - 0, /* %T */ - 0, /* %V */ - ARGS_DELIM, /* Ac */ - 0, /* Ao */ - ARGS_DELIM, /* Aq */ - ARGS_DELIM, /* At */ - ARGS_DELIM, /* Bc */ - 0, /* Bf */ - 0, /* Bo */ - ARGS_DELIM, /* Bq */ - ARGS_DELIM, /* Bsx */ - ARGS_DELIM, /* Bx */ - 0, /* Db */ - ARGS_DELIM, /* Dc */ - 0, /* Do */ - ARGS_DELIM, /* Dq */ - ARGS_DELIM, /* Ec */ - 0, /* Ef */ - ARGS_DELIM, /* Em */ - 0, /* Eo */ - ARGS_DELIM, /* Fx */ - ARGS_DELIM, /* Ms */ - ARGS_DELIM, /* No */ - ARGS_DELIM, /* Ns */ - ARGS_DELIM, /* Nx */ - ARGS_DELIM, /* Ox */ - ARGS_DELIM, /* Pc */ - ARGS_DELIM, /* Pf */ - 0, /* Po */ - ARGS_DELIM, /* Pq */ - ARGS_DELIM, /* Qc */ - ARGS_DELIM, /* Ql */ - 0, /* Qo */ - ARGS_DELIM, /* Qq */ - 0, /* Re */ - 0, /* Rs */ - ARGS_DELIM, /* Sc */ - 0, /* So */ - ARGS_DELIM, /* Sq */ - 0, /* Sm */ - ARGS_DELIM, /* Sx */ - ARGS_DELIM, /* Sy */ - ARGS_DELIM, /* Tn */ - ARGS_DELIM, /* Ux */ - ARGS_DELIM, /* Xc */ - 0, /* Xo */ - 0, /* Fo */ - 0, /* Fc */ - 0, /* Oo */ - ARGS_DELIM, /* Oc */ - 0, /* Bk */ - 0, /* Ek */ - 0, /* Bt */ - 0, /* Hf */ - 0, /* Fr */ - 0, /* Ud */ - 0, /* Lb */ - 0, /* Lp */ - ARGS_DELIM, /* Lk */ - ARGS_DELIM, /* Mt */ - ARGS_DELIM, /* Brq */ - 0, /* Bro */ - ARGS_DELIM, /* Brc */ - 0, /* %C */ - 0, /* Es */ - 0, /* En */ - 0, /* Dx */ - 0, /* %Q */ - 0, /* br */ - 0, /* sp */ - 0, /* %U */ - 0, /* Ta */ +static const enum mdocargt args_Ex[] = { + MDOC_Std, + MDOC_ARG_MAX +}; + +static const enum mdocargt args_An[] = { + MDOC_Split, + MDOC_Nosplit, + MDOC_ARG_MAX +}; + +static const enum mdocargt args_Bd[] = { + MDOC_Ragged, + MDOC_Unfilled, + MDOC_Filled, + MDOC_Literal, + MDOC_File, + MDOC_Offset, + MDOC_Compact, + MDOC_Centred, + MDOC_ARG_MAX +}; + +static const enum mdocargt args_Bf[] = { + MDOC_Emphasis, + MDOC_Literal, + MDOC_Symbolic, + MDOC_ARG_MAX +}; + +static const enum mdocargt args_Bk[] = { + MDOC_Words, + MDOC_ARG_MAX +}; + +static const enum mdocargt args_Bl[] = { + MDOC_Bullet, + MDOC_Dash, + MDOC_Hyphen, + MDOC_Item, + MDOC_Enum, + MDOC_Tag, + MDOC_Diag, + MDOC_Hang, + MDOC_Ohang, + MDOC_Inset, + MDOC_Column, + MDOC_Width, + MDOC_Offset, + MDOC_Compact, + MDOC_Nested, + MDOC_ARG_MAX +}; + +static const struct mdocarg mdocargs[MDOC_MAX] = { + { ARGSFL_NONE, NULL }, /* Ap */ + { ARGSFL_NONE, NULL }, /* Dd */ + { ARGSFL_NONE, NULL }, /* Dt */ + { ARGSFL_NONE, NULL }, /* Os */ + { ARGSFL_NONE, NULL }, /* Sh */ + { ARGSFL_NONE, NULL }, /* Ss */ + { ARGSFL_NONE, NULL }, /* Pp */ + { ARGSFL_DELIM, NULL }, /* D1 */ + { ARGSFL_DELIM, NULL }, /* Dl */ + { ARGSFL_NONE, args_Bd }, /* Bd */ + { ARGSFL_NONE, NULL }, /* Ed */ + { ARGSFL_NONE, args_Bl }, /* Bl */ + { ARGSFL_NONE, NULL }, /* El */ + { ARGSFL_NONE, NULL }, /* It */ + { ARGSFL_DELIM, NULL }, /* Ad */ + { ARGSFL_DELIM, args_An }, /* An */ + { ARGSFL_DELIM, NULL }, /* Ar */ + { ARGSFL_NONE, NULL }, /* Cd */ + { ARGSFL_DELIM, NULL }, /* Cm */ + { ARGSFL_DELIM, NULL }, /* Dv */ + { ARGSFL_DELIM, NULL }, /* Er */ + { ARGSFL_DELIM, NULL }, /* Ev */ + { ARGSFL_NONE, args_Ex }, /* Ex */ + { ARGSFL_DELIM, NULL }, /* Fa */ + { ARGSFL_NONE, NULL }, /* Fd */ + { ARGSFL_DELIM, NULL }, /* Fl */ + { ARGSFL_DELIM, NULL }, /* Fn */ + { ARGSFL_DELIM, NULL }, /* Ft */ + { ARGSFL_DELIM, NULL }, /* Ic */ + { ARGSFL_NONE, NULL }, /* In */ + { ARGSFL_DELIM, NULL }, /* Li */ + { ARGSFL_NONE, NULL }, /* Nd */ + { ARGSFL_DELIM, NULL }, /* Nm */ + { ARGSFL_DELIM, NULL }, /* Op */ + { ARGSFL_NONE, NULL }, /* Ot */ + { ARGSFL_DELIM, NULL }, /* Pa */ + { ARGSFL_NONE, args_Ex }, /* Rv */ + { ARGSFL_DELIM, NULL }, /* St */ + { ARGSFL_DELIM, NULL }, /* Va */ + { ARGSFL_DELIM, NULL }, /* Vt */ + { ARGSFL_DELIM, NULL }, /* Xr */ + { ARGSFL_NONE, NULL }, /* %A */ + { ARGSFL_NONE, NULL }, /* %B */ + { ARGSFL_NONE, NULL }, /* %D */ + { ARGSFL_NONE, NULL }, /* %I */ + { ARGSFL_NONE, NULL }, /* %J */ + { ARGSFL_NONE, NULL }, /* %N */ + { ARGSFL_NONE, NULL }, /* %O */ + { ARGSFL_NONE, NULL }, /* %P */ + { ARGSFL_NONE, NULL }, /* %R */ + { ARGSFL_NONE, NULL }, /* %T */ + { ARGSFL_NONE, NULL }, /* %V */ + { ARGSFL_DELIM, NULL }, /* Ac */ + { ARGSFL_NONE, NULL }, /* Ao */ + { ARGSFL_DELIM, NULL }, /* Aq */ + { ARGSFL_DELIM, NULL }, /* At */ + { ARGSFL_DELIM, NULL }, /* Bc */ + { ARGSFL_NONE, args_Bf }, /* Bf */ + { ARGSFL_NONE, NULL }, /* Bo */ + { ARGSFL_DELIM, NULL }, /* Bq */ + { ARGSFL_DELIM, NULL }, /* Bsx */ + { ARGSFL_DELIM, NULL }, /* Bx */ + { ARGSFL_NONE, NULL }, /* Db */ + { ARGSFL_DELIM, NULL }, /* Dc */ + { ARGSFL_NONE, NULL }, /* Do */ + { ARGSFL_DELIM, NULL }, /* Dq */ + { ARGSFL_DELIM, NULL }, /* Ec */ + { ARGSFL_NONE, NULL }, /* Ef */ + { ARGSFL_DELIM, NULL }, /* Em */ + { ARGSFL_NONE, NULL }, /* Eo */ + { ARGSFL_DELIM, NULL }, /* Fx */ + { ARGSFL_DELIM, NULL }, /* Ms */ + { ARGSFL_DELIM, NULL }, /* No */ + { ARGSFL_DELIM, NULL }, /* Ns */ + { ARGSFL_DELIM, NULL }, /* Nx */ + { ARGSFL_DELIM, NULL }, /* Ox */ + { ARGSFL_DELIM, NULL }, /* Pc */ + { ARGSFL_DELIM, NULL }, /* Pf */ + { ARGSFL_NONE, NULL }, /* Po */ + { ARGSFL_DELIM, NULL }, /* Pq */ + { ARGSFL_DELIM, NULL }, /* Qc */ + { ARGSFL_DELIM, NULL }, /* Ql */ + { ARGSFL_NONE, NULL }, /* Qo */ + { ARGSFL_DELIM, NULL }, /* Qq */ + { ARGSFL_NONE, NULL }, /* Re */ + { ARGSFL_NONE, NULL }, /* Rs */ + { ARGSFL_DELIM, NULL }, /* Sc */ + { ARGSFL_NONE, NULL }, /* So */ + { ARGSFL_DELIM, NULL }, /* Sq */ + { ARGSFL_NONE, NULL }, /* Sm */ + { ARGSFL_DELIM, NULL }, /* Sx */ + { ARGSFL_DELIM, NULL }, /* Sy */ + { ARGSFL_DELIM, NULL }, /* Tn */ + { ARGSFL_DELIM, NULL }, /* Ux */ + { ARGSFL_DELIM, NULL }, /* Xc */ + { ARGSFL_NONE, NULL }, /* Xo */ + { ARGSFL_NONE, NULL }, /* Fo */ + { ARGSFL_NONE, NULL }, /* Fc */ + { ARGSFL_NONE, NULL }, /* Oo */ + { ARGSFL_DELIM, NULL }, /* Oc */ + { ARGSFL_NONE, args_Bk }, /* Bk */ + { ARGSFL_NONE, NULL }, /* Ek */ + { ARGSFL_NONE, NULL }, /* Bt */ + { ARGSFL_NONE, NULL }, /* Hf */ + { ARGSFL_NONE, NULL }, /* Fr */ + { ARGSFL_NONE, NULL }, /* Ud */ + { ARGSFL_NONE, NULL }, /* Lb */ + { ARGSFL_NONE, NULL }, /* Lp */ + { ARGSFL_DELIM, NULL }, /* Lk */ + { ARGSFL_DELIM, NULL }, /* Mt */ + { ARGSFL_DELIM, NULL }, /* Brq */ + { ARGSFL_NONE, NULL }, /* Bro */ + { ARGSFL_DELIM, NULL }, /* Brc */ + { ARGSFL_NONE, NULL }, /* %C */ + { ARGSFL_NONE, NULL }, /* Es */ + { ARGSFL_NONE, NULL }, /* En */ + { ARGSFL_NONE, NULL }, /* Dx */ + { ARGSFL_NONE, NULL }, /* %Q */ + { ARGSFL_NONE, NULL }, /* br */ + { ARGSFL_NONE, NULL }, /* sp */ + { ARGSFL_NONE, NULL }, /* %U */ + { ARGSFL_NONE, NULL }, /* Ta */ }; @@ -226,52 +283,81 @@ mdoc_argv(struct mdoc *m, int line, enum mdoct tok, char *p, sv; struct mdoc_argv tmp; struct mdoc_arg *arg; + const enum mdocargt *ap; if ('\0' == buf[*pos]) return(ARGV_EOLN); + else if (NULL == (ap = mdocargs[tok].argvs)) + return(ARGV_WORD); + else if ('-' != buf[*pos]) + return(ARGV_WORD); - assert(' ' != buf[*pos]); - - /* Parse through to the first unescaped space. */ + /* Seek to the first unescaped space. */ p = &buf[++(*pos)]; assert(*pos > 0); - /* LINTED */ - while (buf[*pos]) { - if (' ' == buf[*pos]) - if ('\\' != buf[*pos - 1]) - break; - (*pos)++; - } + for ( ; buf[*pos] ; (*pos)++) + if (' ' == buf[*pos] && '\\' != buf[*pos - 1]) + break; - /* XXX - save zeroed byte, if not an argument. */ + /* + * We want to nil-terminate the word to look it up (it's easier + * that way). But we may not have a flag, in which case we need + * to restore the line as-is. So keep around the stray byte, + * which we'll reset upon exiting (if necessary). + */ - sv = '\0'; - if (buf[*pos]) { - sv = buf[*pos]; + if ('\0' != (sv = buf[*pos])) buf[(*pos)++] = '\0'; - } - (void)memset(&tmp, 0, sizeof(struct mdoc_argv)); + /* + * Now look up the word as a flag. Use temporary storage that + * we'll copy into the node's flags, if necessary. + */ + + memset(&tmp, 0, sizeof(struct mdoc_argv)); + tmp.line = line; tmp.pos = *pos; + tmp.arg = MDOC_ARG_MAX; - /* See if our token accepts the argument. */ + while (MDOC_ARG_MAX != (tmp.arg = *ap++)) + if (0 == strcmp(p, mdoc_argnames[tmp.arg])) + break; - if (MDOC_ARG_MAX == (tmp.arg = argv_a2arg(tok, p))) { - /* XXX - restore saved zeroed byte. */ + if (MDOC_ARG_MAX == tmp.arg) { + /* + * The flag was not found. + * Restore saved zeroed byte and return as a word. + */ if (sv) buf[*pos - 1] = sv; return(ARGV_WORD); } + /* Read to the next word (the argument). */ + while (buf[*pos] && ' ' == buf[*pos]) (*pos)++; - if ( ! argv(m, line, &tmp, pos, buf)) - return(ARGV_ERROR); + switch (argvflags[tmp.arg]) { + case (ARGV_SINGLE): + if ( ! argv_single(m, line, &tmp, pos, buf)) + return(ARGV_ERROR); + break; + case (ARGV_MULTI): + if ( ! argv_multi(m, line, &tmp, pos, buf)) + return(ARGV_ERROR); + break; + case (ARGV_OPT_SINGLE): + if ( ! argv_opt_single(m, line, &tmp, pos, buf)) + return(ARGV_ERROR); + break; + case (ARGV_NONE): + break; + } if (NULL == (arg = *v)) arg = *v = mandoc_calloc(1, sizeof(struct mdoc_arg)); @@ -280,13 +366,12 @@ mdoc_argv(struct mdoc *m, int line, enum mdoct tok, arg->argv = mandoc_realloc (arg->argv, arg->argc * sizeof(struct mdoc_argv)); - (void)memcpy(&arg->argv[(int)arg->argc - 1], + memcpy(&arg->argv[(int)arg->argc - 1], &tmp, sizeof(struct mdoc_argv)); return(ARGV_ARG); } - void mdoc_argv_free(struct mdoc_arg *p) { @@ -303,15 +388,14 @@ mdoc_argv_free(struct mdoc_arg *p) assert(p->argc); for (i = (int)p->argc - 1; i >= 0; i--) - mdoc_argn_free(p, i); + argn_free(p, i); free(p->argv); free(p); } - -void -mdoc_argn_free(struct mdoc_arg *p, int iarg) +static void +argn_free(struct mdoc_arg *p, int iarg) { struct mdoc_argv *arg; int j; @@ -328,24 +412,21 @@ mdoc_argn_free(struct mdoc_arg *p, int iarg) p->argv[iarg] = p->argv[iarg+1]; } - enum margserr -mdoc_zargs(struct mdoc *m, int line, int *pos, - char *buf, int flags, char **v) +mdoc_zargs(struct mdoc *m, int line, int *pos, char *buf, char **v) { - return(args(m, line, pos, buf, flags, v)); + return(args(m, line, pos, buf, ARGSFL_NONE, v)); } - enum margserr mdoc_args(struct mdoc *m, int line, int *pos, char *buf, enum mdoct tok, char **v) { - int fl; + enum argsflag fl; struct mdoc_node *n; - fl = mdoc_argflags[tok]; + fl = mdocargs[tok].flags; if (MDOC_It != tok) return(args(m, line, pos, buf, fl, v)); @@ -359,42 +440,20 @@ mdoc_args(struct mdoc *m, int line, int *pos, for (n = m->last; n; n = n->parent) if (MDOC_Bl == n->tok) - break; - - if (n && LIST_column == n->norm->Bl.type) { - fl |= ARGS_TABSEP; - fl &= ~ARGS_DELIM; - } + if (LIST_column == n->norm->Bl.type) { + fl = ARGSFL_TABSEP; + break; + } return(args(m, line, pos, buf, fl, v)); } - static enum margserr args(struct mdoc *m, int line, int *pos, - char *buf, int fl, char **v) + char *buf, enum argsflag fl, char **v) { - int i; char *p, *pp; enum margserr rc; - enum mdelim d; - - /* - * Parse out the terms (like `val' in `.Xx -arg val' or simply - * `.Xx val'), which can have all sorts of properties: - * - * ARGS_DELIM: use special handling if encountering trailing - * delimiters in the form of [[::delim::][ ]+]+. - * - * ARGS_NOWARN: don't post warnings. This is only used when - * re-parsing delimiters, as the warnings have already been - * posted. - * - * ARGS_TABSEP: use special handling for tab/`Ta' separated - * phrases like in `Bl -column'. - */ - - assert(' ' != buf[*pos]); if ('\0' == buf[*pos]) { if (MDOC_PPHRASE & m->flags) @@ -405,47 +464,18 @@ args(struct mdoc *m, int line, int *pos, * is unterminated. */ if (MDOC_PHRASELIT & m->flags) - if ( ! mdoc_pmsg(m, line, *pos, MANDOCERR_BADQUOTE)) - return(ARGS_ERROR); + mdoc_pmsg(m, line, *pos, MANDOCERR_BADQUOTE); m->flags &= ~MDOC_PHRASELIT; return(ARGS_EOLN); } - /* - * If the first character is a closing delimiter and we're to - * look for delimited strings, then pass down the buffer seeing - * if it follows the pattern of [[::delim::][ ]+]+. Note that - * we ONLY care about closing delimiters. - */ - - if ((fl & ARGS_DELIM) && DELIM_CLOSE == mdoc_iscdelim(buf[*pos])) { - for (i = *pos; buf[i]; ) { - d = mdoc_iscdelim(buf[i]); - if (DELIM_NONE == d || DELIM_OPEN == d) - break; - i++; - if ('\0' == buf[i] || ' ' != buf[i]) - break; - i++; - while (buf[i] && ' ' == buf[i]) - i++; - } - - if ('\0' == buf[i]) { - *v = &buf[*pos]; - if (i && ' ' != buf[i - 1]) - return(ARGS_PUNCT); - if (ARGS_NOWARN & fl) - return(ARGS_PUNCT); - if ( ! mdoc_pmsg(m, line, *pos, MANDOCERR_EOLNSPACE)) - return(ARGS_ERROR); - return(ARGS_PUNCT); - } - } - *v = &buf[*pos]; + if (ARGSFL_DELIM == fl) + if (args_checkpunct(buf, *pos)) + return(ARGS_PUNCT); + /* * First handle TABSEP items, restricted to `Bl -column'. This * ignores conventional token parsing and instead uses tabs or @@ -453,7 +483,7 @@ args(struct mdoc *m, int line, int *pos, * for arguments at a later phase. */ - if (ARGS_TABSEP & fl) { + if (ARGSFL_TABSEP == fl) { /* Scan ahead to tab (can't be escaped). */ p = strchr(*v, '\t'); pp = NULL; @@ -492,9 +522,8 @@ args(struct mdoc *m, int line, int *pos, } /* Whitespace check for eoln case... */ - if ('\0' == *p && ' ' == *(p - 1) && ! (ARGS_NOWARN & fl)) - if ( ! mdoc_pmsg(m, line, *pos, MANDOCERR_EOLNSPACE)) - return(ARGS_ERROR); + if ('\0' == *p && ' ' == *(p - 1)) + mdoc_pmsg(m, line, *pos, MANDOCERR_EOLNSPACE); *pos += (int)(p - *v); @@ -536,10 +565,9 @@ args(struct mdoc *m, int line, int *pos, } if ('\0' == buf[*pos]) { - if (ARGS_NOWARN & fl || MDOC_PPHRASE & m->flags) + if (MDOC_PPHRASE & m->flags) return(ARGS_QWORD); - if ( ! mdoc_pmsg(m, line, *pos, MANDOCERR_BADQUOTE)) - return(ARGS_ERROR); + mdoc_pmsg(m, line, *pos, MANDOCERR_BADQUOTE); return(ARGS_QWORD); } @@ -552,138 +580,68 @@ args(struct mdoc *m, int line, int *pos, while (' ' == buf[*pos]) (*pos)++; - if (0 == buf[*pos] && ! (ARGS_NOWARN & fl)) - if ( ! mdoc_pmsg(m, line, *pos, MANDOCERR_EOLNSPACE)) - return(ARGS_ERROR); + if ('\0' == buf[*pos]) + mdoc_pmsg(m, line, *pos, MANDOCERR_EOLNSPACE); return(ARGS_QWORD); } - /* - * A non-quoted term progresses until either the end of line or - * a non-escaped whitespace. - */ - - for ( ; buf[*pos]; (*pos)++) - if (*pos && ' ' == buf[*pos] && '\\' != buf[*pos - 1]) - break; - - if ('\0' == buf[*pos]) - return(ARGS_WORD); - - buf[(*pos)++] = '\0'; - - while (' ' == buf[*pos]) - (*pos)++; - - if ('\0' == buf[*pos] && ! (ARGS_NOWARN & fl)) - if ( ! mdoc_pmsg(m, line, *pos, MANDOCERR_EOLNSPACE)) - return(ARGS_ERROR); + p = &buf[*pos]; + *v = mandoc_getarg(m->parse, &p, line, pos); return(ARGS_WORD); } - -static enum mdocargt -argv_a2arg(enum mdoct tok, const char *p) +/* + * Check if the string consists only of space-separated closing + * delimiters. This is a bit of a dance: the first must be a close + * delimiter, but it may be followed by middle delimiters. Arbitrary + * whitespace may separate these tokens. + */ +static int +args_checkpunct(const char *buf, int i) { + int j; + char dbuf[DELIMSZ]; + enum mdelim d; - /* - * Parse an argument identifier from its text. XXX - this - * should really be table-driven to clarify the code. - * - * If you add an argument to the list, make sure that you - * register it here with its one or more macros! - */ + /* First token must be a close-delimiter. */ - switch (tok) { - case (MDOC_An): - if (0 == strcmp(p, "split")) - return(MDOC_Split); - else if (0 == strcmp(p, "nosplit")) - return(MDOC_Nosplit); - break; + for (j = 0; buf[i] && ' ' != buf[i] && j < DELIMSZ; j++, i++) + dbuf[j] = buf[i]; - case (MDOC_Bd): - if (0 == strcmp(p, "ragged")) - return(MDOC_Ragged); - else if (0 == strcmp(p, "unfilled")) - return(MDOC_Unfilled); - else if (0 == strcmp(p, "filled")) - return(MDOC_Filled); - else if (0 == strcmp(p, "literal")) - return(MDOC_Literal); - else if (0 == strcmp(p, "file")) - return(MDOC_File); - else if (0 == strcmp(p, "offset")) - return(MDOC_Offset); - else if (0 == strcmp(p, "compact")) - return(MDOC_Compact); - else if (0 == strcmp(p, "centered")) - return(MDOC_Centred); - break; + if (DELIMSZ == j) + return(0); - case (MDOC_Bf): - if (0 == strcmp(p, "emphasis")) - return(MDOC_Emphasis); - else if (0 == strcmp(p, "literal")) - return(MDOC_Literal); - else if (0 == strcmp(p, "symbolic")) - return(MDOC_Symbolic); - break; + dbuf[j] = '\0'; + if (DELIM_CLOSE != mdoc_isdelim(dbuf)) + return(0); - case (MDOC_Bk): - if (0 == strcmp(p, "words")) - return(MDOC_Words); - break; + while (' ' == buf[i]) + i++; - case (MDOC_Bl): - if (0 == strcmp(p, "bullet")) - return(MDOC_Bullet); - else if (0 == strcmp(p, "dash")) - return(MDOC_Dash); - else if (0 == strcmp(p, "hyphen")) - return(MDOC_Hyphen); - else if (0 == strcmp(p, "item")) - return(MDOC_Item); - else if (0 == strcmp(p, "enum")) - return(MDOC_Enum); - else if (0 == strcmp(p, "tag")) - return(MDOC_Tag); - else if (0 == strcmp(p, "diag")) - return(MDOC_Diag); - else if (0 == strcmp(p, "hang")) - return(MDOC_Hang); - else if (0 == strcmp(p, "ohang")) - return(MDOC_Ohang); - else if (0 == strcmp(p, "inset")) - return(MDOC_Inset); - else if (0 == strcmp(p, "column")) - return(MDOC_Column); - else if (0 == strcmp(p, "width")) - return(MDOC_Width); - else if (0 == strcmp(p, "offset")) - return(MDOC_Offset); - else if (0 == strcmp(p, "compact")) - return(MDOC_Compact); - else if (0 == strcmp(p, "nested")) - return(MDOC_Nested); - break; + /* Remaining must NOT be open/none. */ - case (MDOC_Rv): - /* FALLTHROUGH */ - case (MDOC_Ex): - if (0 == strcmp(p, "std")) - return(MDOC_Std); - break; - default: - break; + while (buf[i]) { + j = 0; + while (buf[i] && ' ' != buf[i] && j < DELIMSZ) + dbuf[j++] = buf[i++]; + + if (DELIMSZ == j) + return(0); + + dbuf[j] = '\0'; + d = mdoc_isdelim(dbuf); + if (DELIM_NONE == d || DELIM_OPEN == d) + return(0); + + while (' ' == buf[i]) + i++; } - return(MDOC_ARG_MAX); + return('\0' == buf[i]); } - static int argv_multi(struct mdoc *m, int line, struct mdoc_argv *v, int *pos, char *buf) @@ -694,7 +652,7 @@ argv_multi(struct mdoc *m, int line, for (v->sz = 0; ; v->sz++) { if ('-' == buf[*pos]) break; - ac = args(m, line, pos, buf, 0, &p); + ac = args(m, line, pos, buf, ARGSFL_NONE, &p); if (ARGS_ERROR == ac) return(0); else if (ARGS_EOLN == ac) @@ -710,7 +668,6 @@ argv_multi(struct mdoc *m, int line, return(1); } - static int argv_opt_single(struct mdoc *m, int line, struct mdoc_argv *v, int *pos, char *buf) @@ -721,7 +678,7 @@ argv_opt_single(struct mdoc *m, int line, if ('-' == buf[*pos]) return(1); - ac = args(m, line, pos, buf, 0, &p); + ac = args(m, line, pos, buf, ARGSFL_NONE, &p); if (ARGS_ERROR == ac) return(0); if (ARGS_EOLN == ac) @@ -734,10 +691,6 @@ argv_opt_single(struct mdoc *m, int line, return(1); } - -/* - * Parse a single, mandatory value from the stream. - */ static int argv_single(struct mdoc *m, int line, struct mdoc_argv *v, int *pos, char *buf) @@ -748,7 +701,7 @@ argv_single(struct mdoc *m, int line, ppos = *pos; - ac = args(m, line, pos, buf, 0, &p); + ac = args(m, line, pos, buf, ARGSFL_NONE, &p); if (ARGS_EOLN == ac) { mdoc_pmsg(m, line, ppos, MANDOCERR_SYNTARGVCOUNT); return(0); @@ -761,32 +714,3 @@ argv_single(struct mdoc *m, int line, return(1); } - - -/* - * Determine rules for parsing arguments. Arguments can either accept - * no parameters, an optional single parameter, one parameter, or - * multiple parameters. - */ -static int -argv(struct mdoc *mdoc, int line, - struct mdoc_argv *v, int *pos, char *buf) -{ - - v->sz = 0; - v->value = NULL; - - switch (mdoc_argvflags[v->arg]) { - case (ARGV_SINGLE): - return(argv_single(mdoc, line, v, pos, buf)); - case (ARGV_MULTI): - return(argv_multi(mdoc, line, v, pos, buf)); - case (ARGV_OPT_SINGLE): - return(argv_opt_single(mdoc, line, v, pos, buf)); - default: - /* ARGV_NONE */ - break; - } - - return(1); -} diff --git a/external/bsd/mdocml/dist/mdoc_hash.c b/external/bsd/mdocml/dist/mdoc_hash.c index ee68246c2..ad44f4942 100644 --- a/external/bsd/mdocml/dist/mdoc_hash.c +++ b/external/bsd/mdocml/dist/mdoc_hash.c @@ -1,4 +1,4 @@ -/* $Vendor-Id: mdoc_hash.c,v 1.16 2010/06/19 20:46:28 kristaps Exp $ */ +/* $Vendor-Id: mdoc_hash.c,v 1.18 2011/07/24 18:15:14 kristaps Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -27,10 +27,11 @@ #include <stdio.h> #include <string.h> +#include "mdoc.h" #include "mandoc.h" #include "libmdoc.h" -static u_char table[27 * 12]; +static unsigned char table[27 * 12]; /* * XXX - this hash has global scope, so if intended for use as a library @@ -47,14 +48,14 @@ mdoc_hash_init(void) for (i = 0; i < (int)MDOC_MAX; i++) { p = mdoc_macronames[i]; - if (isalpha((u_char)p[1])) - major = 12 * (tolower((u_char)p[1]) - 97); + if (isalpha((unsigned char)p[1])) + major = 12 * (tolower((unsigned char)p[1]) - 97); else major = 12 * 26; for (j = 0; j < 12; j++) if (UCHAR_MAX == table[major + j]) { - table[major + j] = (u_char)i; + table[major + j] = (unsigned char)i; break; } @@ -69,11 +70,11 @@ mdoc_hash_find(const char *p) if (0 == p[0]) return(MDOC_MAX); - if ( ! isalpha((u_char)p[0]) && '%' != p[0]) + if ( ! isalpha((unsigned char)p[0]) && '%' != p[0]) return(MDOC_MAX); - if (isalpha((u_char)p[1])) - major = 12 * (tolower((u_char)p[1]) - 97); + if (isalpha((unsigned char)p[1])) + major = 12 * (tolower((unsigned char)p[1]) - 97); else if ('1' == p[1]) major = 12 * 26; else diff --git a/external/bsd/mdocml/dist/mdoc_html.c b/external/bsd/mdocml/dist/mdoc_html.c index 1201354e1..0b21fcaa5 100644 --- a/external/bsd/mdocml/dist/mdoc_html.c +++ b/external/bsd/mdocml/dist/mdoc_html.c @@ -1,6 +1,6 @@ -/* $Vendor-Id: mdoc_html.c,v 1.142 2011/01/07 13:20:58 kristaps Exp $ */ +/* $Vendor-Id: mdoc_html.c,v 1.182 2011/11/03 20:37:00 schwarze Exp $ */ /* - * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -34,7 +34,6 @@ #include "main.h" #define INDENT 5 -#define HALFINDENT 3 #define MDOC_ARGS const struct mdoc_meta *m, \ const struct mdoc_node *n, \ @@ -190,7 +189,7 @@ static const struct htmlmdoc mdocs[MDOC_MAX] = { {NULL, NULL}, /* Ec */ /* FIXME: no space */ {NULL, NULL}, /* Ef */ {mdoc_em_pre, NULL}, /* Em */ - {NULL, NULL}, /* Eo */ + {mdoc_quote_pre, mdoc_quote_post}, /* Eo */ {mdoc_xx_pre, NULL}, /* Fx */ {mdoc_ms_pre, NULL}, /* Ms */ {mdoc_igndelim_pre, NULL}, /* No */ @@ -263,17 +262,9 @@ static const char * const lists[LIST_MAX] = { void html_mdoc(void *arg, const struct mdoc *m) { - struct html *h; - struct tag *t; - h = (struct html *)arg; - - print_gen_decls(h); - t = print_otag(h, TAG_HTML, 0, NULL); - print_mdoc(mdoc_meta(m), mdoc_node(m), h); - print_tagq(h, t); - - printf("\n"); + print_mdoc(mdoc_meta(m), mdoc_node(m), (struct html *)arg); + putchar('\n'); } @@ -288,7 +279,7 @@ a2width(const char *p, struct roffsu *su) if ( ! a2roffsu(p, su, SCALE_MAX)) { su->unit = SCALE_BU; - su->scale = (int)strlen(p); + su->scale = html_strlen(p); } } @@ -353,23 +344,30 @@ a2offs(const char *p, struct roffsu *su) SCALE_HS_INIT(su, INDENT); else if (0 == strcmp(p, "indent-two")) SCALE_HS_INIT(su, INDENT * 2); - else if ( ! a2roffsu(p, su, SCALE_MAX)) { - su->unit = SCALE_BU; - su->scale = (int)strlen(p); - } + else if ( ! a2roffsu(p, su, SCALE_MAX)) + SCALE_HS_INIT(su, html_strlen(p)); } static void print_mdoc(MDOC_ARGS) { - struct tag *t; + struct tag *t, *tt; + struct htmlpair tag; - t = print_otag(h, TAG_HEAD, 0, NULL); - print_mdoc_head(m, n, h); - print_tagq(h, t); + PAIR_CLASS_INIT(&tag, "mandoc"); + + if ( ! (HTML_FRAGMENT & h->oflags)) { + print_gen_decls(h); + t = print_otag(h, TAG_HTML, 0, NULL); + tt = print_otag(h, TAG_HEAD, 0, NULL); + print_mdoc_head(m, n, h); + print_tagq(h, tt); + print_otag(h, TAG_BODY, 0, NULL); + print_otag(h, TAG_DIV, 1, &tag); + } else + t = print_otag(h, TAG_DIV, 1, &tag); - t = print_otag(h, TAG_BODY, 0, NULL); print_mdoc_nodelist(m, n, h); print_tagq(h, t); } @@ -382,13 +380,10 @@ print_mdoc_head(MDOC_ARGS) print_gen_head(h); bufinit(h); - buffmt(h, "%s(%s)", m->title, m->msec); + bufcat_fmt(h, "%s(%s)", m->title, m->msec); - if (m->arch) { - bufcat(h, " ("); - bufcat(h, m->arch); - bufcat(h, ")"); - } + if (m->arch) + bufcat_fmt(h, " (%s)", m->arch); print_otag(h, TAG_TITLE, 0, NULL); print_text(h, h->buf); @@ -414,18 +409,50 @@ print_mdoc_node(MDOC_ARGS) child = 1; t = h->tags.head; - bufinit(h); switch (n->type) { case (MDOC_ROOT): child = mdoc_root_pre(m, n, h); break; case (MDOC_TEXT): + /* No tables in this mode... */ + assert(NULL == h->tblt); + + /* + * Make sure that if we're in a literal mode already + * (i.e., within a <PRE>) don't print the newline. + */ + if (' ' == *n->string && MDOC_LINE & n->flags) + if ( ! (HTML_LITERAL & h->flags)) + print_otag(h, TAG_BR, 0, NULL); + if (MDOC_DELIMC & n->flags) + h->flags |= HTML_NOSPACE; print_text(h, n->string); + if (MDOC_DELIMO & n->flags) + h->flags |= HTML_NOSPACE; return; - case (MDOC_TBL): - print_tbl(h, n->span); + case (MDOC_EQN): + print_eqn(h, n->eqn); break; + case (MDOC_TBL): + /* + * This will take care of initialising all of the table + * state data for the first table, then tearing it down + * for the last one. + */ + print_tbl(h, n->span); + return; default: + /* + * Close out the current table, if it's open, and unset + * the "meta" table state. This will be reopened on the + * next table element. + */ + if (h->tblt) { + print_tblclose(h); + t = h->tags.head; + } + + assert(NULL == h->tblt); if (mdocs[n->tok].pre && ENDBODY_NOT == n->end) child = (*mdocs[n->tok].pre)(m, n, h); break; @@ -448,12 +475,11 @@ print_mdoc_node(MDOC_ARGS) print_stagq(h, t); - bufinit(h); switch (n->type) { case (MDOC_ROOT): mdoc_root_post(m, n, h); break; - case (MDOC_TBL): + case (MDOC_EQN): break; default: if (mdocs[n->tok].post && ENDBODY_NOT == n->end) @@ -468,38 +494,27 @@ mdoc_root_post(MDOC_ARGS) { struct htmlpair tag[3]; struct tag *t, *tt; - char b[DATESIZ]; - - time2a(m->date, b, DATESIZ); PAIR_SUMMARY_INIT(&tag[0], "Document Footer"); PAIR_CLASS_INIT(&tag[1], "foot"); - if (NULL == h->style) { - PAIR_INIT(&tag[2], ATTR_WIDTH, "100%"); - t = print_otag(h, TAG_TABLE, 3, tag); - PAIR_INIT(&tag[0], ATTR_WIDTH, "50%"); - print_otag(h, TAG_COL, 1, tag); - print_otag(h, TAG_COL, 1, tag); - } else - t = print_otag(h, TAG_TABLE, 2, tag); + PAIR_INIT(&tag[2], ATTR_WIDTH, "100%"); + t = print_otag(h, TAG_TABLE, 3, tag); + PAIR_INIT(&tag[0], ATTR_WIDTH, "50%"); + print_otag(h, TAG_COL, 1, tag); + print_otag(h, TAG_COL, 1, tag); - t = print_otag(h, TAG_TBODY, 0, NULL); + print_otag(h, TAG_TBODY, 0, NULL); tt = print_otag(h, TAG_TR, 0, NULL); PAIR_CLASS_INIT(&tag[0], "foot-date"); print_otag(h, TAG_TD, 1, tag); - - print_text(h, b); + print_text(h, m->date); print_stagq(h, tt); PAIR_CLASS_INIT(&tag[0], "foot-os"); - if (NULL == h->style) { - PAIR_INIT(&tag[1], ATTR_ALIGN, "right"); - print_otag(h, TAG_TD, 2, tag); - } else - print_otag(h, TAG_TD, 1, tag); - + PAIR_INIT(&tag[1], ATTR_ALIGN, "right"); + print_otag(h, TAG_TD, 2, tag); print_text(h, m->os); print_tagq(h, t); } @@ -525,15 +540,12 @@ mdoc_root_pre(MDOC_ARGS) PAIR_SUMMARY_INIT(&tag[0], "Document Header"); PAIR_CLASS_INIT(&tag[1], "head"); - if (NULL == h->style) { - PAIR_INIT(&tag[2], ATTR_WIDTH, "100%"); - t = print_otag(h, TAG_TABLE, 3, tag); - PAIR_INIT(&tag[0], ATTR_WIDTH, "30%"); - print_otag(h, TAG_COL, 1, tag); - print_otag(h, TAG_COL, 1, tag); - print_otag(h, TAG_COL, 1, tag); - } else - t = print_otag(h, TAG_TABLE, 2, tag); + PAIR_INIT(&tag[2], ATTR_WIDTH, "100%"); + t = print_otag(h, TAG_TABLE, 3, tag); + PAIR_INIT(&tag[0], ATTR_WIDTH, "30%"); + print_otag(h, TAG_COL, 1, tag); + print_otag(h, TAG_COL, 1, tag); + print_otag(h, TAG_COL, 1, tag); print_otag(h, TAG_TBODY, 0, NULL); @@ -541,27 +553,18 @@ mdoc_root_pre(MDOC_ARGS) PAIR_CLASS_INIT(&tag[0], "head-ltitle"); print_otag(h, TAG_TD, 1, tag); - print_text(h, title); print_stagq(h, tt); PAIR_CLASS_INIT(&tag[0], "head-vol"); - if (NULL == h->style) { - PAIR_INIT(&tag[1], ATTR_ALIGN, "center"); - print_otag(h, TAG_TD, 2, tag); - } else - print_otag(h, TAG_TD, 1, tag); - + PAIR_INIT(&tag[1], ATTR_ALIGN, "center"); + print_otag(h, TAG_TD, 2, tag); print_text(h, b); print_stagq(h, tt); PAIR_CLASS_INIT(&tag[0], "head-rtitle"); - if (NULL == h->style) { - PAIR_INIT(&tag[1], ATTR_ALIGN, "right"); - print_otag(h, TAG_TD, 2, tag); - } else - print_otag(h, TAG_TD, 1, tag); - + PAIR_INIT(&tag[1], ATTR_ALIGN, "right"); + print_otag(h, TAG_TD, 2, tag); print_text(h, title); print_tagq(h, t); return(1); @@ -573,7 +576,6 @@ static int mdoc_sh_pre(MDOC_ARGS) { struct htmlpair tag; - char buf[BUFSIZ]; if (MDOC_BLOCK == n->type) { PAIR_CLASS_INIT(&tag, "section"); @@ -582,25 +584,29 @@ mdoc_sh_pre(MDOC_ARGS) } else if (MDOC_BODY == n->type) return(1); - buf[0] = '\0'; - for (n = n->child; n; n = n->next) { - html_idcat(buf, n->string, BUFSIZ); - if (n->next) - html_idcat(buf, " ", BUFSIZ); + bufinit(h); + bufcat(h, "x"); + + for (n = n->child; n && MDOC_TEXT == n->type; ) { + bufcat_id(h, n->string); + if (NULL != (n = n->next)) + bufcat_id(h, " "); } - PAIR_ID_INIT(&tag, buf); - print_otag(h, TAG_H1, 1, &tag); + if (NULL == n) { + PAIR_ID_INIT(&tag, h->buf); + print_otag(h, TAG_H1, 1, &tag); + } else + print_otag(h, TAG_H1, 0, NULL); + return(1); } - /* ARGSUSED */ static int mdoc_ss_pre(MDOC_ARGS) { struct htmlpair tag; - char buf[BUFSIZ]; if (MDOC_BLOCK == n->type) { PAIR_CLASS_INIT(&tag, "subsection"); @@ -609,15 +615,21 @@ mdoc_ss_pre(MDOC_ARGS) } else if (MDOC_BODY == n->type) return(1); - buf[0] = '\0'; - for (n = n->child; n; n = n->next) { - html_idcat(buf, n->string, BUFSIZ); - if (n->next) - html_idcat(buf, " ", BUFSIZ); + bufinit(h); + bufcat(h, "x"); + + for (n = n->child; n && MDOC_TEXT == n->type; ) { + bufcat_id(h, n->string); + if (NULL != (n = n->next)) + bufcat_id(h, " "); } - PAIR_ID_INIT(&tag, buf); - print_otag(h, TAG_H2, 1, &tag); + if (NULL == n) { + PAIR_ID_INIT(&tag, h->buf); + print_otag(h, TAG_H2, 1, &tag); + } else + print_otag(h, TAG_H2, 0, NULL); + return(1); } @@ -670,7 +682,7 @@ mdoc_nm_pre(MDOC_ARGS) { struct htmlpair tag; struct roffsu su; - size_t len; + int len; switch (n->type) { case (MDOC_ELEM): @@ -698,12 +710,13 @@ mdoc_nm_pre(MDOC_ARGS) for (len = 0, n = n->child; n; n = n->next) if (MDOC_TEXT == n->type) - len += strlen(n->string); + len += html_strlen(n->string); if (0 == len && m->name) - len = strlen(m->name); + len = html_strlen(m->name); SCALE_HS_INIT(&su, (double)len); + bufinit(h); bufcat_su(h, "width", &su); PAIR_STYLE_INIT(&tag, h); print_otag(h, TAG_COL, 1, &tag); @@ -718,8 +731,7 @@ mdoc_nm_pre(MDOC_ARGS) static int mdoc_xr_pre(MDOC_ARGS) { - struct htmlpair tag[2]; - const struct mdoc_node *nn; + struct htmlpair tag[2]; if (NULL == n->child) return(0); @@ -735,16 +747,16 @@ mdoc_xr_pre(MDOC_ARGS) } else print_otag(h, TAG_A, 1, tag); - nn = n->child; - print_text(h, nn->string); + n = n->child; + print_text(h, n->string); - if (NULL == (nn = nn->next)) + if (NULL == (n = n->next)) return(0); h->flags |= HTML_NOSPACE; print_text(h, "("); h->flags |= HTML_NOSPACE; - print_text(h, nn->string); + print_text(h, n->string); h->flags |= HTML_NOSPACE; print_text(h, ")"); return(0); @@ -756,7 +768,8 @@ static int mdoc_ns_pre(MDOC_ARGS) { - h->flags |= HTML_NOSPACE; + if ( ! (MDOC_LINE & n->flags)) + h->flags |= HTML_NOSPACE; return(1); } @@ -779,6 +792,7 @@ mdoc_xx_pre(MDOC_ARGS) { const char *pp; struct htmlpair tag; + int flags; switch (n->tok) { case (MDOC_Bsx): @@ -805,8 +819,15 @@ mdoc_xx_pre(MDOC_ARGS) PAIR_CLASS_INIT(&tag, "unix"); print_otag(h, TAG_SPAN, 1, &tag); + print_text(h, pp); - return(1); + if (n->child) { + flags = h->flags; + h->flags |= HTML_KEEP; + print_text(h, n->child->string); + h->flags = flags; + } + return(0); } @@ -814,19 +835,27 @@ mdoc_xx_pre(MDOC_ARGS) static int mdoc_bx_pre(MDOC_ARGS) { - const struct mdoc_node *nn; - struct htmlpair tag; + struct htmlpair tag; PAIR_CLASS_INIT(&tag, "unix"); print_otag(h, TAG_SPAN, 1, &tag); - for (nn = n->child; nn; nn = nn->next) - print_mdoc_node(m, nn, h); - - if (n->child) + if (NULL != (n = n->child)) { + print_text(h, n->string); h->flags |= HTML_NOSPACE; + print_text(h, "BSD"); + } else { + print_text(h, "BSD"); + return(0); + } + + if (NULL != (n = n->next)) { + h->flags |= HTML_NOSPACE; + print_text(h, "-"); + h->flags |= HTML_NOSPACE; + print_text(h, n->string); + } - print_text(h, "BSD"); return(0); } @@ -850,6 +879,8 @@ mdoc_it_pre(MDOC_ARGS) assert(lists[type]); PAIR_CLASS_INIT(&tag[0], lists[type]); + bufinit(h); + if (MDOC_HEAD == n->type) { switch (type) { case(LIST_bullet): @@ -950,6 +981,8 @@ mdoc_bl_pre(MDOC_ARGS) struct roffsu su; char buf[BUFSIZ]; + bufinit(h); + if (MDOC_BODY == n->type) { if (LIST_column == n->norm->Bl.type) print_otag(h, TAG_TBODY, 0, NULL); @@ -969,7 +1002,6 @@ mdoc_bl_pre(MDOC_ARGS) for (i = 0; i < (int)n->norm->Bl.ncols; i++) { a2width(n->norm->Bl.cols[i], &su); - bufinit(h); if (i < (int)n->norm->Bl.ncols - 1) bufcat_su(h, "width", &su); else @@ -1037,9 +1069,9 @@ mdoc_bl_pre(MDOC_ARGS) static int mdoc_ex_pre(MDOC_ARGS) { - const struct mdoc_node *nn; - struct tag *t; - struct htmlpair tag; + struct tag *t; + struct htmlpair tag; + int nchild; if (n->prev) print_otag(h, TAG_BR, 0, NULL); @@ -1047,22 +1079,25 @@ mdoc_ex_pre(MDOC_ARGS) PAIR_CLASS_INIT(&tag, "utility"); print_text(h, "The"); - for (nn = n->child; nn; nn = nn->next) { + + nchild = n->nchild; + for (n = n->child; n; n = n->next) { + assert(MDOC_TEXT == n->type); + t = print_otag(h, TAG_B, 1, &tag); - print_text(h, nn->string); + print_text(h, n->string); print_tagq(h, t); - h->flags |= HTML_NOSPACE; - - if (nn->next && NULL == nn->next->next) - print_text(h, ", and"); - else if (nn->next) + if (nchild > 2 && n->next) { + h->flags |= HTML_NOSPACE; print_text(h, ","); - else - h->flags &= ~HTML_NOSPACE; + } + + if (n->next && NULL == n->next->next) + print_text(h, "and"); } - if (n->child && n->child->next) + if (nchild > 1) print_text(h, "utilities exit"); else print_text(h, "utility exits"); @@ -1095,6 +1130,7 @@ mdoc_d1_pre(MDOC_ARGS) return(1); SCALE_VS_INIT(&su, 0); + bufinit(h); bufcat_su(h, "margin-top", &su); bufcat_su(h, "margin-bottom", &su); PAIR_STYLE_INIT(&tag[0], h); @@ -1118,19 +1154,19 @@ mdoc_d1_pre(MDOC_ARGS) static int mdoc_sx_pre(MDOC_ARGS) { - struct htmlpair tag[2]; - const struct mdoc_node *nn; - char buf[BUFSIZ]; + struct htmlpair tag[2]; - strlcpy(buf, "#", BUFSIZ); - for (nn = n->child; nn; nn = nn->next) { - html_idcat(buf, nn->string, BUFSIZ); - if (nn->next) - html_idcat(buf, " ", BUFSIZ); + bufinit(h); + bufcat(h, "#x"); + + for (n = n->child; n; ) { + bufcat_id(h, n->string); + if (NULL != (n = n->next)) + bufcat_id(h, " "); } PAIR_CLASS_INIT(&tag[0], "link-sec"); - PAIR_HREF_INIT(&tag[1], buf); + PAIR_HREF_INIT(&tag[1], h->buf); print_otag(h, TAG_I, 1, tag); print_otag(h, TAG_A, 2, tag); @@ -1143,7 +1179,7 @@ static int mdoc_bd_pre(MDOC_ARGS) { struct htmlpair tag[2]; - int comp; + int comp, sv; const struct mdoc_node *nn; struct roffsu su; @@ -1168,7 +1204,8 @@ mdoc_bd_pre(MDOC_ARGS) SCALE_HS_INIT(&su, 0); if (n->norm->Bd.offs) a2offs(n->norm->Bd.offs, &su); - + + bufinit(h); bufcat_su(h, "margin-left", &su); PAIR_STYLE_INIT(&tag[0], h); @@ -1182,6 +1219,11 @@ mdoc_bd_pre(MDOC_ARGS) PAIR_CLASS_INIT(&tag[1], "lit display"); print_otag(h, TAG_PRE, 2, tag); + /* This can be recursive: save & set our literal state. */ + + sv = h->flags & HTML_LITERAL; + h->flags |= HTML_LITERAL; + for (nn = n->child; nn; nn = nn->next) { print_mdoc_node(m, nn, h); /* @@ -1218,6 +1260,9 @@ mdoc_bd_pre(MDOC_ARGS) h->flags |= HTML_NOSPACE; } + if (0 == sv) + h->flags &= ~HTML_LITERAL; + return(0); } @@ -1327,12 +1372,16 @@ mdoc_fa_pre(MDOC_ARGS) t = print_otag(h, TAG_I, 1, &tag); print_text(h, nn->string); print_tagq(h, t); - if (nn->next) + if (nn->next) { + h->flags |= HTML_NOSPACE; print_text(h, ","); + } } - if (n->child && n->next && n->next->tok == MDOC_Fa) + if (n->child && n->next && n->next->tok == MDOC_Fa) { + h->flags |= HTML_NOSPACE; print_text(h, ","); + } return(0); } @@ -1342,13 +1391,60 @@ mdoc_fa_pre(MDOC_ARGS) static int mdoc_fd_pre(MDOC_ARGS) { - struct htmlpair tag; + struct htmlpair tag[2]; + char buf[BUFSIZ]; + size_t sz; + int i; + struct tag *t; synopsis_pre(h, n); - PAIR_CLASS_INIT(&tag, "macro"); - print_otag(h, TAG_B, 1, &tag); - return(1); + if (NULL == (n = n->child)) + return(0); + + assert(MDOC_TEXT == n->type); + + if (strcmp(n->string, "#include")) { + PAIR_CLASS_INIT(&tag[0], "macro"); + print_otag(h, TAG_B, 1, tag); + return(1); + } + + PAIR_CLASS_INIT(&tag[0], "includes"); + print_otag(h, TAG_B, 1, tag); + print_text(h, n->string); + + if (NULL != (n = n->next)) { + assert(MDOC_TEXT == n->type); + strlcpy(buf, '<' == *n->string || '"' == *n->string ? + n->string + 1 : n->string, BUFSIZ); + + sz = strlen(buf); + if (sz && ('>' == buf[sz - 1] || '"' == buf[sz - 1])) + buf[sz - 1] = '\0'; + + PAIR_CLASS_INIT(&tag[0], "link-includes"); + + i = 1; + if (h->base_includes) { + buffmt_includes(h, buf); + PAIR_HREF_INIT(&tag[i], h->buf); + i++; + } + + t = print_otag(h, TAG_A, i, tag); + print_text(h, n->string); + print_tagq(h, t); + + n = n->next; + } + + for ( ; n; n = n->next) { + assert(MDOC_TEXT == n->type); + print_text(h, n->string); + } + + return(0); } @@ -1389,13 +1485,13 @@ mdoc_ft_pre(MDOC_ARGS) static int mdoc_fn_pre(MDOC_ARGS) { - struct tag *t; - struct htmlpair tag[2]; - const struct mdoc_node *nn; - char nbuf[BUFSIZ]; - const char *sp, *ep; - int sz, i; + struct tag *t; + struct htmlpair tag[2]; + char nbuf[BUFSIZ]; + const char *sp, *ep; + int sz, i, pretty; + pretty = MDOC_SYNPRETTY & n->flags; synopsis_pre(h, n); /* Split apart into type and name. */ @@ -1447,26 +1543,33 @@ mdoc_fn_pre(MDOC_ARGS) h->flags |= HTML_NOSPACE; print_text(h, "("); + h->flags |= HTML_NOSPACE; - bufinit(h); PAIR_CLASS_INIT(&tag[0], "farg"); + bufinit(h); bufcat_style(h, "white-space", "nowrap"); PAIR_STYLE_INIT(&tag[1], h); - for (nn = n->child->next; nn; nn = nn->next) { + for (n = n->child->next; n; n = n->next) { i = 1; if (MDOC_SYNPRETTY & n->flags) i = 2; t = print_otag(h, TAG_I, i, tag); - print_text(h, nn->string); + print_text(h, n->string); print_tagq(h, t); - if (nn->next) + if (n->next) { + h->flags |= HTML_NOSPACE; print_text(h, ","); + } } + h->flags |= HTML_NOSPACE; print_text(h, ")"); - if (MDOC_SYNPRETTY & n->flags) + + if (pretty) { + h->flags |= HTML_NOSPACE; print_text(h, ";"); + } return(0); } @@ -1517,11 +1620,13 @@ mdoc_sp_pre(MDOC_ARGS) SCALE_VS_INIT(&su, 1); if (MDOC_sp == n->tok) { - if (n->child) - a2roffsu(n->child->string, &su, SCALE_VS); + if (NULL != (n = n->child)) + if ( ! a2roffsu(n->string, &su, SCALE_VS)) + SCALE_VS_INIT(&su, atoi(n->string)); } else su.scale = 0; + bufinit(h); bufcat_su(h, "height", &su); PAIR_STYLE_INIT(&tag, h); print_otag(h, TAG_DIV, 1, &tag); @@ -1537,20 +1642,23 @@ mdoc_sp_pre(MDOC_ARGS) static int mdoc_lk_pre(MDOC_ARGS) { - const struct mdoc_node *nn; - struct htmlpair tag[2]; + struct htmlpair tag[2]; - nn = n->child; + if (NULL == (n = n->child)) + return(0); + + assert(MDOC_TEXT == n->type); PAIR_CLASS_INIT(&tag[0], "link-ext"); - PAIR_HREF_INIT(&tag[1], nn->string); + PAIR_HREF_INIT(&tag[1], n->string); + print_otag(h, TAG_A, 2, tag); - if (NULL == nn || NULL == nn->next) - return(1); + if (NULL == n->next) + print_text(h, n->string); - for (nn = nn->next; nn; nn = nn->next) - print_text(h, nn->string); + for (n = n->next; n; n = n->next) + print_text(h, n->string); return(0); } @@ -1560,19 +1668,21 @@ mdoc_lk_pre(MDOC_ARGS) static int mdoc_mt_pre(MDOC_ARGS) { - struct htmlpair tag[2]; - struct tag *t; - const struct mdoc_node *nn; + struct htmlpair tag[2]; + struct tag *t; PAIR_CLASS_INIT(&tag[0], "link-mail"); - for (nn = n->child; nn; nn = nn->next) { + for (n = n->child; n; n = n->next) { + assert(MDOC_TEXT == n->type); + bufinit(h); bufcat(h, "mailto:"); - bufcat(h, nn->string); + bufcat(h, n->string); + PAIR_HREF_INIT(&tag[1], h->buf); t = print_otag(h, TAG_A, 2, tag); - print_text(h, nn->string); + print_text(h, n->string); print_tagq(h, t); } @@ -1617,7 +1727,9 @@ mdoc_fo_post(MDOC_ARGS) if (MDOC_BODY != n->type) return; + h->flags |= HTML_NOSPACE; print_text(h, ")"); + h->flags |= HTML_NOSPACE; print_text(h, ";"); } @@ -1626,39 +1738,55 @@ mdoc_fo_post(MDOC_ARGS) static int mdoc_in_pre(MDOC_ARGS) { - const struct mdoc_node *nn; - struct tag *t; - struct htmlpair tag[2]; - int i; + struct tag *t; + struct htmlpair tag[2]; + int i; synopsis_pre(h, n); PAIR_CLASS_INIT(&tag[0], "includes"); print_otag(h, TAG_B, 1, tag); + /* + * The first argument of the `In' gets special treatment as + * being a linked value. Subsequent values are printed + * afterward. groff does similarly. This also handles the case + * of no children. + */ + if (MDOC_SYNPRETTY & n->flags && MDOC_LINE & n->flags) print_text(h, "#include"); print_text(h, "<"); h->flags |= HTML_NOSPACE; - for (nn = n->child; nn; nn = nn->next) { + if (NULL != (n = n->child)) { + assert(MDOC_TEXT == n->type); + PAIR_CLASS_INIT(&tag[0], "link-includes"); + i = 1; - bufinit(h); if (h->base_includes) { - buffmt_includes(h, nn->string); + buffmt_includes(h, n->string); PAIR_HREF_INIT(&tag[i], h->buf); i++; - } + } + t = print_otag(h, TAG_A, i, tag); - print_mdoc_node(m, nn, h); + print_text(h, n->string); print_tagq(h, t); + + n = n->next; } h->flags |= HTML_NOSPACE; print_text(h, ">"); + for ( ; n; n = n->next) { + assert(MDOC_TEXT == n->type); + print_text(h, n->string); + } + return(0); } @@ -1679,31 +1807,38 @@ mdoc_ic_pre(MDOC_ARGS) static int mdoc_rv_pre(MDOC_ARGS) { - const struct mdoc_node *nn; - struct htmlpair tag; - struct tag *t; + struct htmlpair tag; + struct tag *t; + int nchild; if (n->prev) print_otag(h, TAG_BR, 0, NULL); + PAIR_CLASS_INIT(&tag, "fname"); + print_text(h, "The"); - for (nn = n->child; nn; nn = nn->next) { - PAIR_CLASS_INIT(&tag, "fname"); + nchild = n->nchild; + for (n = n->child; n; n = n->next) { + assert(MDOC_TEXT == n->type); + t = print_otag(h, TAG_B, 1, &tag); - print_text(h, nn->string); + print_text(h, n->string); print_tagq(h, t); h->flags |= HTML_NOSPACE; - if (nn->next && NULL == nn->next->next) - print_text(h, "(), and"); - else if (nn->next) - print_text(h, "(),"); - else - print_text(h, "()"); + print_text(h, "()"); + + if (nchild > 2 && n->next) { + h->flags |= HTML_NOSPACE; + print_text(h, ","); + } + + if (n->next && NULL == n->next->next) + print_text(h, "and"); } - if (n->child && n->child->next) + if (nchild > 1) print_text(h, "functions return"); else print_text(h, "function returns"); @@ -1769,6 +1904,7 @@ mdoc_bf_pre(MDOC_ARGS) * We want this to be inline-formatted, but needs to be div to * accept block children. */ + bufinit(h); bufcat_style(h, "display", "inline"); SCALE_HS_INIT(&su, 1); /* Needs a left-margin for spacing. */ @@ -1836,7 +1972,7 @@ mdoc_li_pre(MDOC_ARGS) struct htmlpair tag; PAIR_CLASS_INIT(&tag, "lit"); - print_otag(h, TAG_SPAN, 1, &tag); + print_otag(h, TAG_CODE, 1, &tag); return(1); } @@ -1978,6 +2114,7 @@ mdoc__x_post(MDOC_ARGS) if (NULL == n->parent || MDOC_Rs != n->parent->tok) return; + h->flags |= HTML_NOSPACE; print_text(h, n->next ? "," : "."); } @@ -2048,6 +2185,8 @@ mdoc_quote_pre(MDOC_ARGS) PAIR_CLASS_INIT(&tag, "opt"); print_otag(h, TAG_SPAN, 1, &tag); break; + case (MDOC_Eo): + break; case (MDOC_Do): /* FALLTHROUGH */ case (MDOC_Dq): @@ -2063,7 +2202,11 @@ mdoc_quote_pre(MDOC_ARGS) print_text(h, "("); break; case (MDOC_Ql): - /* FALLTHROUGH */ + print_text(h, "\\(oq"); + h->flags |= HTML_NOSPACE; + PAIR_CLASS_INIT(&tag, "lit"); + print_otag(h, TAG_CODE, 1, &tag); + break; case (MDOC_So): /* FALLTHROUGH */ case (MDOC_Sq): @@ -2109,6 +2252,8 @@ mdoc_quote_post(MDOC_ARGS) case (MDOC_Bq): print_text(h, "\\(rB"); break; + case (MDOC_Eo): + break; case (MDOC_Qo): /* FALLTHROUGH */ case (MDOC_Qq): diff --git a/external/bsd/mdocml/dist/mdoc_macro.c b/external/bsd/mdocml/dist/mdoc_macro.c index b47a59143..98a18a386 100644 --- a/external/bsd/mdocml/dist/mdoc_macro.c +++ b/external/bsd/mdocml/dist/mdoc_macro.c @@ -1,6 +1,6 @@ -/* $Vendor-Id: mdoc_macro.c,v 1.99 2010/12/15 23:39:40 kristaps Exp $ */ +/* $Vendor-Id: mdoc_macro.c,v 1.115 2012/01/05 00:43:51 schwarze Exp $ */ /* - * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any @@ -26,6 +26,7 @@ #include <string.h> #include <time.h> +#include "mdoc.h" #include "mandoc.h" #include "libmdoc.h" #include "libmandoc.h" @@ -50,6 +51,8 @@ static int in_line(MACRO_PROT_ARGS); static int obsolete(MACRO_PROT_ARGS); static int phrase_ta(MACRO_PROT_ARGS); +static int dword(struct mdoc *, int, int, + const char *, enum mdelim); static int append_delims(struct mdoc *, int, int *, char *); static enum mdoct lookup(enum mdoct, const char *); @@ -71,8 +74,8 @@ const struct mdoc_macro __mdoc_macros[MDOC_MAX] = { { in_line_eoln, MDOC_PROLOGUE }, /* Dd */ { in_line_eoln, MDOC_PROLOGUE }, /* Dt */ { in_line_eoln, MDOC_PROLOGUE }, /* Os */ - { blk_full, 0 }, /* Sh */ - { blk_full, 0 }, /* Ss */ + { blk_full, MDOC_PARSED }, /* Sh */ + { blk_full, MDOC_PARSED }, /* Ss */ { in_line_eoln, 0 }, /* Pp */ { blk_part_imp, MDOC_PARSED }, /* D1 */ { blk_part_imp, MDOC_PARSED }, /* Dl */ @@ -225,7 +228,6 @@ mdoc_macroend(struct mdoc *m) static enum mdoct lookup(enum mdoct from, const char *p) { - /* FIXME: make -diag lists be un-PARSED. */ if ( ! (MDOC_PARSED & mdoc_macros[from].flags)) return(MDOC_MAX); @@ -252,17 +254,24 @@ lookup_raw(const char *p) static int rew_last(struct mdoc *mdoc, const struct mdoc_node *to) { - struct mdoc_node *n; + struct mdoc_node *n, *np; assert(to); mdoc->next = MDOC_NEXT_SIBLING; /* LINTED */ while (mdoc->last != to) { + /* + * Save the parent here, because we may delete the + * m->last node in the post-validation phase and reset + * it to m->last->parent, causing a step in the closing + * out to be lost. + */ + np = mdoc->last->parent; if ( ! mdoc_valid_post(mdoc)) return(0); n = mdoc->last; - mdoc->last = mdoc->last->parent; + mdoc->last = np; assert(mdoc->last); mdoc->last->last = n; } @@ -506,9 +515,9 @@ make_pending(struct mdoc_node *broken, enum mdoct tok, taker->pending = broken->pending; } broken->pending = breaker; - mdoc_vmsg(m, MANDOCERR_SCOPENEST, line, ppos, - "%s breaks %s", mdoc_macronames[tok], - mdoc_macronames[broken->tok]); + mandoc_vmsg(MANDOCERR_SCOPENEST, m->parse, line, ppos, + "%s breaks %s", mdoc_macronames[tok], + mdoc_macronames[broken->tok]); return(1); } @@ -534,9 +543,10 @@ rew_sub(enum mdoc_type t, struct mdoc *m, case (REWIND_THIS): break; case (REWIND_FORCE): - mdoc_vmsg(m, MANDOCERR_SCOPEBROKEN, line, ppos, - "%s breaks %s", mdoc_macronames[tok], - mdoc_macronames[n->tok]); + mandoc_vmsg(MANDOCERR_SCOPEBROKEN, m->parse, + line, ppos, "%s breaks %s", + mdoc_macronames[tok], + mdoc_macronames[n->tok]); /* FALLTHROUGH */ case (REWIND_MORE): n = n->parent; @@ -572,6 +582,40 @@ rew_sub(enum mdoc_type t, struct mdoc *m, return(1); } +/* + * Allocate a word and check whether it's punctuation or not. + * Punctuation consists of those tokens found in mdoc_isdelim(). + */ +static int +dword(struct mdoc *m, int line, + int col, const char *p, enum mdelim d) +{ + + if (DELIM_MAX == d) + d = mdoc_isdelim(p); + + if ( ! mdoc_word_alloc(m, line, col, p)) + return(0); + + if (DELIM_OPEN == d) + m->last->flags |= MDOC_DELIMO; + + /* + * Closing delimiters only suppress the preceding space + * when they follow something, not when they start a new + * block or element, and not when they follow `No'. + * + * XXX Explicitly special-casing MDOC_No here feels + * like a layering violation. Find a better way + * and solve this in the code related to `No'! + */ + + else if (DELIM_CLOSE == d && m->last->prev && + m->last->prev->tok != MDOC_No) + m->last->flags |= MDOC_DELIMC; + + return(1); +} static int append_delims(struct mdoc *m, int line, int *pos, char *buf) @@ -585,27 +629,25 @@ append_delims(struct mdoc *m, int line, int *pos, char *buf) for (;;) { la = *pos; - ac = mdoc_zargs(m, line, pos, buf, ARGS_NOWARN, &p); + ac = mdoc_zargs(m, line, pos, buf, &p); if (ARGS_ERROR == ac) return(0); else if (ARGS_EOLN == ac) break; - assert(DELIM_NONE != mdoc_isdelim(p)); - if ( ! mdoc_word_alloc(m, line, la, p)) - return(0); + dword(m, line, la, p, DELIM_MAX); /* * If we encounter end-of-sentence symbols, then trigger * the double-space. * - * XXX: it's easy to allow this to propogate outward to + * XXX: it's easy to allow this to propagate outward to * the last symbol, such that `. )' will cause the * correct double-spacing. However, (1) groff isn't * smart enough to do this and (2) it would require * knowing which symbols break this behaviour, for - * example, `. ;' shouldn't propogate the double-space. + * example, `. ;' shouldn't propagate the double-space. */ if (mandoc_eos(p, strlen(p), 0)) m->last->flags |= MDOC_EOS; @@ -703,8 +745,7 @@ blk_exp_close(MACRO_PROT_ARGS) if ( ! (MDOC_CALLABLE & mdoc_macros[tok].flags)) { /* FIXME: do this in validate */ if (buf[*pos]) - if ( ! mdoc_pmsg(m, line, ppos, MANDOCERR_ARGSLOST)) - return(0); + mdoc_pmsg(m, line, ppos, MANDOCERR_ARGSLOST); if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos)) return(0); @@ -739,7 +780,7 @@ blk_exp_close(MACRO_PROT_ARGS) ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p); if (MDOC_MAX == ntok) { - if ( ! mdoc_word_alloc(m, line, lastarg, p)) + if ( ! dword(m, line, lastarg, p, DELIM_MAX)) return(0); continue; } @@ -847,9 +888,9 @@ in_line(MACRO_PROT_ARGS) return(0); } else if ( ! nc && 0 == cnt) { mdoc_argv_free(arg); - if ( ! mdoc_pmsg(m, line, ppos, MANDOCERR_MACROEMPTY)) - return(0); + mdoc_pmsg(m, line, ppos, MANDOCERR_MACROEMPTY); } + if ( ! mdoc_macro(m, ntok, line, la, pos, buf)) return(0); if ( ! nl) @@ -898,7 +939,8 @@ in_line(MACRO_PROT_ARGS) if (DELIM_NONE == d) cnt++; - if ( ! mdoc_word_alloc(m, line, la, p)) + + if ( ! dword(m, line, la, p, d)) return(0); /* @@ -929,8 +971,7 @@ in_line(MACRO_PROT_ARGS) return(0); } else if ( ! nc && 0 == cnt) { mdoc_argv_free(arg); - if ( ! mdoc_pmsg(m, line, ppos, MANDOCERR_MACROEMPTY)) - return(0); + mdoc_pmsg(m, line, ppos, MANDOCERR_MACROEMPTY); } if ( ! nl) @@ -942,7 +983,7 @@ in_line(MACRO_PROT_ARGS) static int blk_full(MACRO_PROT_ARGS) { - int la, nl; + int la, nl, nparsed; struct mdoc_arg *arg; struct mdoc_node *head; /* save of head macro */ struct mdoc_node *body; /* save of body macro */ @@ -965,7 +1006,7 @@ blk_full(MACRO_PROT_ARGS) } /* - * This routine accomodates implicitly- and explicitly-scoped + * This routine accommodates implicitly- and explicitly-scoped * macro openings. Implicit ones first close out prior scope * (seen above). Delay opening the head until necessary to * allow leading punctuation to print. Special consideration @@ -996,6 +1037,14 @@ blk_full(MACRO_PROT_ARGS) head = body = NULL; + /* + * Exception: Heads of `It' macros in `-diag' lists are not + * parsed, even though `It' macros in general are parsed. + */ + nparsed = MDOC_It == tok && + MDOC_Bl == m->last->parent->tok && + LIST_diag == m->last->parent->norm->Bl.type; + /* * The `Nd' macro has all arguments in its body: it's a hybrid * of block partial-explicit and full-implicit. Stupid. @@ -1055,7 +1104,7 @@ blk_full(MACRO_PROT_ARGS) ARGS_PPHRASE != ac && ARGS_QWORD != ac && DELIM_OPEN == mdoc_isdelim(p)) { - if ( ! mdoc_word_alloc(m, line, la, p)) + if ( ! dword(m, line, la, p, DELIM_OPEN)) return(0); continue; } @@ -1104,10 +1153,11 @@ blk_full(MACRO_PROT_ARGS) continue; } - ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p); + ntok = nparsed || ARGS_QWORD == ac ? + MDOC_MAX : lookup(tok, p); if (MDOC_MAX == ntok) { - if ( ! mdoc_word_alloc(m, line, la, p)) + if ( ! dword(m, line, la, p, DELIM_MAX)) return(0); continue; } @@ -1217,8 +1267,8 @@ blk_part_imp(MACRO_PROT_ARGS) break; if (NULL == body && ARGS_QWORD != ac && - DELIM_OPEN == mdoc_isdelim(p)) { - if ( ! mdoc_word_alloc(m, line, la, p)) + DELIM_OPEN == mdoc_isdelim(p)) { + if ( ! dword(m, line, la, p, DELIM_OPEN)) return(0); continue; } @@ -1232,7 +1282,7 @@ blk_part_imp(MACRO_PROT_ARGS) ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p); if (MDOC_MAX == ntok) { - if ( ! mdoc_word_alloc(m, line, la, p)) + if ( ! dword(m, line, la, p, DELIM_MAX)) return(0); continue; } @@ -1262,7 +1312,7 @@ blk_part_imp(MACRO_PROT_ARGS) if (mandoc_eos(n->string, strlen(n->string), 1)) n->flags |= MDOC_EOS; - /* Up-propogate the end-of-space flag. */ + /* Up-propagate the end-of-space flag. */ if (n && (MDOC_EOS & n->flags)) { body->flags |= MDOC_EOS; @@ -1292,9 +1342,9 @@ blk_part_imp(MACRO_PROT_ARGS) * is ugly behaviour nodding its head to OpenBSD's overwhelming * crufty use of `Op' breakage. */ - if (n != body && ! mdoc_vmsg(m, MANDOCERR_SCOPENEST, - line, ppos, "%s broken", mdoc_macronames[tok])) - return(0); + if (n != body) + mandoc_vmsg(MANDOCERR_SCOPENEST, m->parse, line, ppos, + "%s broken", mdoc_macronames[tok]); if (n && ! rew_sub(MDOC_BODY, m, tok, line, ppos)) return(0); @@ -1348,9 +1398,9 @@ blk_part_exp(MACRO_PROT_ARGS) /* Flush out leading punctuation. */ if (NULL == head && ARGS_QWORD != ac && - DELIM_OPEN == mdoc_isdelim(p)) { + DELIM_OPEN == mdoc_isdelim(p)) { assert(NULL == body); - if ( ! mdoc_word_alloc(m, line, la, p)) + if ( ! dword(m, line, la, p, DELIM_OPEN)) return(0); continue; } @@ -1371,7 +1421,7 @@ blk_part_exp(MACRO_PROT_ARGS) assert(head); /* No check whether it's a macro! */ if (MDOC_Eo == tok) - if ( ! mdoc_word_alloc(m, line, la, p)) + if ( ! dword(m, line, la, p, DELIM_MAX)) return(0); if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos)) @@ -1389,7 +1439,7 @@ blk_part_exp(MACRO_PROT_ARGS) ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p); if (MDOC_MAX == ntok) { - if ( ! mdoc_word_alloc(m, line, la, p)) + if ( ! dword(m, line, la, p, DELIM_MAX)) return(0); continue; } @@ -1401,18 +1451,15 @@ blk_part_exp(MACRO_PROT_ARGS) /* Clean-up to leave in a consistent state. */ - if (NULL == head) { + if (NULL == head) if ( ! mdoc_head_alloc(m, line, ppos, tok)) return(0); - head = m->last; - } if (NULL == body) { if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos)) return(0); if ( ! mdoc_body_alloc(m, line, ppos, tok)) return(0); - body = m->last; } /* Standard appending of delimiters. */ @@ -1454,6 +1501,8 @@ in_line_argn(MACRO_PROT_ARGS) case (MDOC_Ux): maxargs = 0; break; + case (MDOC_Bx): + /* FALLTHROUGH */ case (MDOC_Xr): maxargs = 2; break; @@ -1492,9 +1541,9 @@ in_line_argn(MACRO_PROT_ARGS) break; if ( ! (MDOC_IGNDELIM & mdoc_macros[tok].flags) && - ARGS_QWORD != ac && - 0 == j && DELIM_OPEN == mdoc_isdelim(p)) { - if ( ! mdoc_word_alloc(m, line, la, p)) + ARGS_QWORD != ac && 0 == j && + DELIM_OPEN == mdoc_isdelim(p)) { + if ( ! dword(m, line, la, p, DELIM_OPEN)) return(0); continue; } else if (0 == j) @@ -1528,23 +1577,7 @@ in_line_argn(MACRO_PROT_ARGS) flushed = 1; } - /* - * XXX: this is a hack to work around groff's ugliness - * as regards `Xr' and extraneous arguments. It should - * ideally be deprecated behaviour, but because this is - * code is no here, it's unlikely to be removed. - */ - -#ifdef __OpenBSD__ - if (MDOC_Xr == tok && j == maxargs) { - if ( ! mdoc_elem_alloc(m, line, la, MDOC_Ns, NULL)) - return(0); - if ( ! rew_elem(m, MDOC_Ns)) - return(0); - } -#endif - - if ( ! mdoc_word_alloc(m, line, la, p)) + if ( ! dword(m, line, la, p, DELIM_MAX)) return(0); j++; } @@ -1615,7 +1648,7 @@ in_line_eoln(MACRO_PROT_ARGS) ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p); if (MDOC_MAX == ntok) { - if ( ! mdoc_word_alloc(m, line, la, p)) + if ( ! dword(m, line, la, p, DELIM_MAX)) return(0); continue; } @@ -1664,7 +1697,8 @@ static int obsolete(MACRO_PROT_ARGS) { - return(mdoc_pmsg(m, line, ppos, MANDOCERR_MACROOBS)); + mdoc_pmsg(m, line, ppos, MANDOCERR_MACROOBS); + return(1); } @@ -1684,7 +1718,7 @@ phrase(struct mdoc *m, int line, int ppos, char *buf) for (pos = ppos; ; ) { la = pos; - ac = mdoc_zargs(m, line, &pos, buf, 0, &p); + ac = mdoc_zargs(m, line, &pos, buf, &p); if (ARGS_ERROR == ac) return(0); @@ -1694,7 +1728,7 @@ phrase(struct mdoc *m, int line, int ppos, char *buf) ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup_raw(p); if (MDOC_MAX == ntok) { - if ( ! mdoc_word_alloc(m, line, la, p)) + if ( ! dword(m, line, la, p, DELIM_MAX)) return(0); continue; } @@ -1729,7 +1763,7 @@ phrase_ta(MACRO_PROT_ARGS) for (;;) { la = *pos; - ac = mdoc_zargs(m, line, pos, buf, 0, &p); + ac = mdoc_zargs(m, line, pos, buf, &p); if (ARGS_ERROR == ac) return(0); @@ -1739,7 +1773,7 @@ phrase_ta(MACRO_PROT_ARGS) ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup_raw(p); if (MDOC_MAX == ntok) { - if ( ! mdoc_word_alloc(m, line, la, p)) + if ( ! dword(m, line, la, p, DELIM_MAX)) return(0); continue; } diff --git a/external/bsd/mdocml/dist/mdoc_man.c b/external/bsd/mdocml/dist/mdoc_man.c new file mode 100644 index 000000000..d60d4b49b --- /dev/null +++ b/external/bsd/mdocml/dist/mdoc_man.c @@ -0,0 +1,637 @@ +/* $Vendor-Id: mdoc_man.c,v 1.9 2011/10/24 21:47:59 schwarze Exp $ */ +/* + * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <string.h> + +#include "mandoc.h" +#include "man.h" +#include "mdoc.h" +#include "main.h" + +#define DECL_ARGS const struct mdoc_meta *m, \ + const struct mdoc_node *n, \ + struct mman *mm + +struct mman { + int need_space; /* next word needs prior ws */ + int need_nl; /* next word needs prior nl */ +}; + +struct manact { + int (*cond)(DECL_ARGS); /* DON'T run actions */ + int (*pre)(DECL_ARGS); /* pre-node action */ + void (*post)(DECL_ARGS); /* post-node action */ + const char *prefix; /* pre-node string constant */ + const char *suffix; /* post-node string constant */ +}; + +static int cond_body(DECL_ARGS); +static int cond_head(DECL_ARGS); +static void post_bd(DECL_ARGS); +static void post_dl(DECL_ARGS); +static void post_enc(DECL_ARGS); +static void post_nm(DECL_ARGS); +static void post_percent(DECL_ARGS); +static void post_pf(DECL_ARGS); +static void post_sect(DECL_ARGS); +static void post_sp(DECL_ARGS); +static int pre_ap(DECL_ARGS); +static int pre_bd(DECL_ARGS); +static int pre_br(DECL_ARGS); +static int pre_bx(DECL_ARGS); +static int pre_dl(DECL_ARGS); +static int pre_enc(DECL_ARGS); +static int pre_it(DECL_ARGS); +static int pre_nm(DECL_ARGS); +static int pre_ns(DECL_ARGS); +static int pre_pp(DECL_ARGS); +static int pre_sp(DECL_ARGS); +static int pre_sect(DECL_ARGS); +static int pre_ux(DECL_ARGS); +static int pre_xr(DECL_ARGS); +static void print_word(struct mman *, const char *); +static void print_node(DECL_ARGS); + +static const struct manact manacts[MDOC_MAX + 1] = { + { NULL, pre_ap, NULL, NULL, NULL }, /* Ap */ + { NULL, NULL, NULL, NULL, NULL }, /* Dd */ + { NULL, NULL, NULL, NULL, NULL }, /* Dt */ + { NULL, NULL, NULL, NULL, NULL }, /* Os */ + { NULL, pre_sect, post_sect, ".SH", NULL }, /* Sh */ + { NULL, pre_sect, post_sect, ".SS", NULL }, /* Ss */ + { NULL, pre_pp, NULL, NULL, NULL }, /* Pp */ + { cond_body, pre_dl, post_dl, NULL, NULL }, /* D1 */ + { cond_body, pre_dl, post_dl, NULL, NULL }, /* Dl */ + { cond_body, pre_bd, post_bd, NULL, NULL }, /* Bd */ + { NULL, NULL, NULL, NULL, NULL }, /* Ed */ + { NULL, NULL, NULL, NULL, NULL }, /* Bl */ + { NULL, NULL, NULL, NULL, NULL }, /* El */ + { NULL, pre_it, NULL, NULL, NULL }, /* _It */ + { NULL, pre_enc, post_enc, "\\fI", "\\fP" }, /* Ad */ + { NULL, NULL, NULL, NULL, NULL }, /* _An */ + { NULL, pre_enc, post_enc, "\\fI", "\\fP" }, /* Ar */ + { NULL, pre_enc, post_enc, "\\fB", "\\fP" }, /* Cd */ + { NULL, pre_enc, post_enc, "\\fB", "\\fP" }, /* Cm */ + { NULL, pre_enc, post_enc, "\\fR", "\\fP" }, /* Dv */ + { NULL, pre_enc, post_enc, "\\fR", "\\fP" }, /* Er */ + { NULL, pre_enc, post_enc, "\\fR", "\\fP" }, /* Ev */ + { NULL, pre_enc, post_enc, "The \\fB", + "\\fP\nutility exits 0 on success, and >0 if an error occurs." + }, /* Ex */ + { NULL, NULL, NULL, NULL, NULL }, /* _Fa */ + { NULL, NULL, NULL, NULL, NULL }, /* _Fd */ + { NULL, pre_enc, post_enc, "\\fB-", "\\fP" }, /* Fl */ + { NULL, NULL, NULL, NULL, NULL }, /* _Fn */ + { NULL, NULL, NULL, NULL, NULL }, /* _Ft */ + { NULL, pre_enc, post_enc, "\\fB", "\\fP" }, /* Ic */ + { NULL, NULL, NULL, NULL, NULL }, /* _In */ + { NULL, pre_enc, post_enc, "\\fR", "\\fP" }, /* Li */ + { cond_head, pre_enc, NULL, "\\- ", NULL }, /* Nd */ + { NULL, pre_nm, post_nm, NULL, NULL }, /* Nm */ + { cond_body, pre_enc, post_enc, "[", "]" }, /* Op */ + { NULL, NULL, NULL, NULL, NULL }, /* Ot */ + { NULL, pre_enc, post_enc, "\\fI", "\\fP" }, /* Pa */ + { NULL, pre_enc, post_enc, "The \\fB", + "\\fP\nfunction returns the value 0 if successful;\n" + "otherwise the value -1 is returned and the global\n" + "variable \\fIerrno\\fP is set to indicate the error." + }, /* Rv */ + { NULL, NULL, NULL, NULL, NULL }, /* St */ + { NULL, NULL, NULL, NULL, NULL }, /* _Va */ + { NULL, NULL, NULL, NULL, NULL }, /* _Vt */ + { NULL, pre_xr, NULL, NULL, NULL }, /* Xr */ + { NULL, NULL, post_percent, NULL, NULL }, /* _%A */ + { NULL, NULL, NULL, NULL, NULL }, /* _%B */ + { NULL, NULL, post_percent, NULL, NULL }, /* _%D */ + { NULL, NULL, NULL, NULL, NULL }, /* _%I */ + { NULL, pre_enc, post_percent, "\\fI", "\\fP" }, /* %J */ + { NULL, NULL, NULL, NULL, NULL }, /* _%N */ + { NULL, NULL, NULL, NULL, NULL }, /* _%O */ + { NULL, NULL, NULL, NULL, NULL }, /* _%P */ + { NULL, NULL, NULL, NULL, NULL }, /* _%R */ + { NULL, pre_enc, post_percent, "\"", "\"" }, /* %T */ + { NULL, NULL, NULL, NULL, NULL }, /* _%V */ + { NULL, NULL, NULL, NULL, NULL }, /* Ac */ + { cond_body, pre_enc, post_enc, "<", ">" }, /* Ao */ + { cond_body, pre_enc, post_enc, "<", ">" }, /* Aq */ + { NULL, NULL, NULL, NULL, NULL }, /* At */ + { NULL, NULL, NULL, NULL, NULL }, /* Bc */ + { NULL, NULL, NULL, NULL, NULL }, /* _Bf */ + { cond_body, pre_enc, post_enc, "[", "]" }, /* Bo */ + { cond_body, pre_enc, post_enc, "[", "]" }, /* Bq */ + { NULL, pre_ux, NULL, "BSD/OS", NULL }, /* Bsx */ + { NULL, pre_bx, NULL, NULL, NULL }, /* Bx */ + { NULL, NULL, NULL, NULL, NULL }, /* Db */ + { NULL, NULL, NULL, NULL, NULL }, /* Dc */ + { cond_body, pre_enc, post_enc, "``", "''" }, /* Do */ + { cond_body, pre_enc, post_enc, "``", "''" }, /* Dq */ + { NULL, NULL, NULL, NULL, NULL }, /* _Ec */ + { NULL, NULL, NULL, NULL, NULL }, /* _Ef */ + { NULL, pre_enc, post_enc, "\\fI", "\\fP" }, /* Em */ + { NULL, NULL, NULL, NULL, NULL }, /* _Eo */ + { NULL, pre_ux, NULL, "FreeBSD", NULL }, /* Fx */ + { NULL, pre_enc, post_enc, "\\fB", "\\fP" }, /* Ms */ + { NULL, NULL, NULL, NULL, NULL }, /* No */ + { NULL, pre_ns, NULL, NULL, NULL }, /* Ns */ + { NULL, pre_ux, NULL, "NetBSD", NULL }, /* Nx */ + { NULL, pre_ux, NULL, "OpenBSD", NULL }, /* Ox */ + { NULL, NULL, NULL, NULL, NULL }, /* Pc */ + { NULL, NULL, post_pf, NULL, NULL }, /* Pf */ + { cond_body, pre_enc, post_enc, "(", ")" }, /* Po */ + { cond_body, pre_enc, post_enc, "(", ")" }, /* Pq */ + { NULL, NULL, NULL, NULL, NULL }, /* Qc */ + { cond_body, pre_enc, post_enc, "`", "'" }, /* Ql */ + { cond_body, pre_enc, post_enc, "\"", "\"" }, /* Qo */ + { cond_body, pre_enc, post_enc, "\"", "\"" }, /* Qq */ + { NULL, NULL, NULL, NULL, NULL }, /* Re */ + { cond_body, pre_pp, NULL, NULL, NULL }, /* Rs */ + { NULL, NULL, NULL, NULL, NULL }, /* Sc */ + { cond_body, pre_enc, post_enc, "`", "'" }, /* So */ + { cond_body, pre_enc, post_enc, "`", "'" }, /* Sq */ + { NULL, NULL, NULL, NULL, NULL }, /* _Sm */ + { NULL, pre_enc, post_enc, "\\fI", "\\fP" }, /* Sx */ + { NULL, pre_enc, post_enc, "\\fB", "\\fP" }, /* Sy */ + { NULL, pre_enc, post_enc, "\\fR", "\\fP" }, /* Tn */ + { NULL, pre_ux, NULL, "UNIX", NULL }, /* Ux */ + { NULL, NULL, NULL, NULL, NULL }, /* _Xc */ + { NULL, NULL, NULL, NULL, NULL }, /* _Xo */ + { NULL, NULL, NULL, NULL, NULL }, /* _Fo */ + { NULL, NULL, NULL, NULL, NULL }, /* _Fc */ + { cond_body, pre_enc, post_enc, "[", "]" }, /* Oo */ + { NULL, NULL, NULL, NULL, NULL }, /* Oc */ + { NULL, NULL, NULL, NULL, NULL }, /* _Bk */ + { NULL, NULL, NULL, NULL, NULL }, /* _Ek */ + { NULL, pre_ux, NULL, "is currently in beta test.", NULL }, /* Bt */ + { NULL, NULL, NULL, NULL, NULL }, /* Hf */ + { NULL, NULL, NULL, NULL, NULL }, /* Fr */ + { NULL, pre_ux, NULL, "currently under development.", NULL }, /* Ud */ + { NULL, NULL, NULL, NULL, NULL }, /* _Lb */ + { NULL, pre_pp, NULL, NULL, NULL }, /* Lp */ + { NULL, NULL, NULL, NULL, NULL }, /* _Lk */ + { NULL, NULL, NULL, NULL, NULL }, /* _Mt */ + { cond_body, pre_enc, post_enc, "{", "}" }, /* Brq */ + { cond_body, pre_enc, post_enc, "{", "}" }, /* Bro */ + { NULL, NULL, NULL, NULL, NULL }, /* Brc */ + { NULL, NULL, NULL, NULL, NULL }, /* _%C */ + { NULL, NULL, NULL, NULL, NULL }, /* _Es */ + { NULL, NULL, NULL, NULL, NULL }, /* _En */ + { NULL, pre_ux, NULL, "DragonFly", NULL }, /* Dx */ + { NULL, NULL, NULL, NULL, NULL }, /* _%Q */ + { NULL, pre_br, NULL, NULL, NULL }, /* br */ + { NULL, pre_sp, post_sp, NULL, NULL }, /* sp */ + { NULL, NULL, NULL, NULL, NULL }, /* _%U */ + { NULL, NULL, NULL, NULL, NULL }, /* _Ta */ + { NULL, NULL, NULL, NULL, NULL }, /* ROOT */ +}; + +static void +print_word(struct mman *mm, const char *s) +{ + + if (mm->need_nl) { + /* + * If we need a newline, print it now and start afresh. + */ + putchar('\n'); + mm->need_space = 0; + mm->need_nl = 0; + } else if (mm->need_space && '\0' != s[0]) + /* + * If we need a space, only print it before + * (1) a nonzero length word; + * (2) a word that is non-punctuation; and + * (3) if punctuation, non-terminating puncutation. + */ + if (NULL == strchr(".,:;)]?!", s[0]) || '\0' != s[1]) + putchar(' '); + + /* + * Reassign needing space if we're not following opening + * punctuation. + */ + mm->need_space = + ('(' != s[0] && '[' != s[0]) || '\0' != s[1]; + + for ( ; *s; s++) { + switch (*s) { + case (ASCII_NBRSP): + printf("\\~"); + break; + case (ASCII_HYPH): + putchar('-'); + break; + default: + putchar((unsigned char)*s); + break; + } + } +} + +void +man_man(void *arg, const struct man *man) +{ + + /* + * Dump the keep buffer. + * We're guaranteed by now that this exists (is non-NULL). + * Flush stdout afterward, just in case. + */ + fputs(mparse_getkeep(man_mparse(man)), stdout); + fflush(stdout); +} + +void +man_mdoc(void *arg, const struct mdoc *mdoc) +{ + const struct mdoc_meta *m; + const struct mdoc_node *n; + struct mman mm; + + m = mdoc_meta(mdoc); + n = mdoc_node(mdoc); + + printf(".TH \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"", + m->title, m->msec, m->date, m->os, m->vol); + + memset(&mm, 0, sizeof(struct mman)); + + mm.need_nl = 1; + print_node(m, n, &mm); + putchar('\n'); +} + +static void +print_node(DECL_ARGS) +{ + const struct mdoc_node *prev, *sub; + const struct manact *act; + int cond, do_sub; + + /* + * Break the line if we were parsed subsequent the current node. + * This makes the page structure be more consistent. + */ + prev = n->prev ? n->prev : n->parent; + if (prev && prev->line < n->line) + mm->need_nl = 1; + + act = NULL; + cond = 0; + do_sub = 1; + + if (MDOC_TEXT == n->type) { + /* + * Make sure that we don't happen to start with a + * control character at the start of a line. + */ + if (mm->need_nl && ('.' == *n->string || + '\'' == *n->string)) { + print_word(mm, "\\&"); + mm->need_space = 0; + } + print_word(mm, n->string); + } else { + /* + * Conditionally run the pre-node action handler for a + * node. + */ + act = manacts + n->tok; + cond = NULL == act->cond || (*act->cond)(m, n, mm); + if (cond && act->pre) + do_sub = (*act->pre)(m, n, mm); + } + + /* + * Conditionally run all child nodes. + * Note that this iterates over children instead of using + * recursion. This prevents unnecessary depth in the stack. + */ + if (do_sub) + for (sub = n->child; sub; sub = sub->next) + print_node(m, sub, mm); + + /* + * Lastly, conditionally run the post-node handler. + */ + if (cond && act->post) + (*act->post)(m, n, mm); +} + +static int +cond_head(DECL_ARGS) +{ + + return(MDOC_HEAD == n->type); +} + +static int +cond_body(DECL_ARGS) +{ + + return(MDOC_BODY == n->type); +} + +/* + * Output a font encoding before a node, e.g., \fR. + * This obviously has no trailing space. + */ +static int +pre_enc(DECL_ARGS) +{ + const char *prefix; + + prefix = manacts[n->tok].prefix; + if (NULL == prefix) + return(1); + print_word(mm, prefix); + mm->need_space = 0; + return(1); +} + +/* + * Output a font encoding subsequent a node, e.g., \fP. + */ +static void +post_enc(DECL_ARGS) +{ + const char *suffix; + + suffix = manacts[n->tok].suffix; + if (NULL == suffix) + return; + mm->need_space = 0; + print_word(mm, suffix); +} + +/* + * Used in listings (percent = %A, e.g.). + * FIXME: this is incomplete. + * It doesn't print a nice ", and" for lists. + */ +static void +post_percent(DECL_ARGS) +{ + + post_enc(m, n, mm); + if (n->next) + print_word(mm, ","); + else { + print_word(mm, "."); + mm->need_nl = 1; + } +} + +/* + * Print before a section header. + */ +static int +pre_sect(DECL_ARGS) +{ + + if (MDOC_HEAD != n->type) + return(1); + mm->need_nl = 1; + print_word(mm, manacts[n->tok].prefix); + print_word(mm, "\""); + mm->need_space = 0; + return(1); +} + +/* + * Print subsequent a section header. + */ +static void +post_sect(DECL_ARGS) +{ + + if (MDOC_HEAD != n->type) + return; + mm->need_space = 0; + print_word(mm, "\""); + mm->need_nl = 1; +} + +static int +pre_ap(DECL_ARGS) +{ + + mm->need_space = 0; + print_word(mm, "'"); + mm->need_space = 0; + return(0); +} + +static int +pre_bd(DECL_ARGS) +{ + + if (DISP_unfilled == n->norm->Bd.type || + DISP_literal == n->norm->Bd.type) { + mm->need_nl = 1; + print_word(mm, ".nf"); + } + mm->need_nl = 1; + return(1); +} + +static void +post_bd(DECL_ARGS) +{ + + if (DISP_unfilled == n->norm->Bd.type || + DISP_literal == n->norm->Bd.type) { + mm->need_nl = 1; + print_word(mm, ".fi"); + } + mm->need_nl = 1; +} + +static int +pre_br(DECL_ARGS) +{ + + mm->need_nl = 1; + print_word(mm, ".br"); + mm->need_nl = 1; + return(0); +} + +static int +pre_bx(DECL_ARGS) +{ + + n = n->child; + if (n) { + print_word(mm, n->string); + mm->need_space = 0; + n = n->next; + } + print_word(mm, "BSD"); + if (NULL == n) + return(0); + mm->need_space = 0; + print_word(mm, "-"); + mm->need_space = 0; + print_word(mm, n->string); + return(0); +} + +static int +pre_dl(DECL_ARGS) +{ + + mm->need_nl = 1; + print_word(mm, ".RS 6n"); + mm->need_nl = 1; + return(1); +} + +static void +post_dl(DECL_ARGS) +{ + + mm->need_nl = 1; + print_word(mm, ".RE"); + mm->need_nl = 1; +} + +static int +pre_it(DECL_ARGS) +{ + const struct mdoc_node *bln; + + if (MDOC_HEAD == n->type) { + mm->need_nl = 1; + print_word(mm, ".TP"); + bln = n->parent->parent->prev; + switch (bln->norm->Bl.type) { + case (LIST_bullet): + print_word(mm, "4n"); + mm->need_nl = 1; + print_word(mm, "\\fBo\\fP"); + break; + default: + if (bln->norm->Bl.width) + print_word(mm, bln->norm->Bl.width); + break; + } + mm->need_nl = 1; + } + return(1); +} + +static int +pre_nm(DECL_ARGS) +{ + + if (MDOC_ELEM != n->type && MDOC_HEAD != n->type) + return(1); + print_word(mm, "\\fB"); + mm->need_space = 0; + if (NULL == n->child) + print_word(mm, m->name); + return(1); +} + +static void +post_nm(DECL_ARGS) +{ + + if (MDOC_ELEM != n->type && MDOC_HEAD != n->type) + return; + mm->need_space = 0; + print_word(mm, "\\fP"); +} + +static int +pre_ns(DECL_ARGS) +{ + + mm->need_space = 0; + return(0); +} + +static void +post_pf(DECL_ARGS) +{ + + mm->need_space = 0; +} + +static int +pre_pp(DECL_ARGS) +{ + + mm->need_nl = 1; + if (MDOC_It == n->parent->tok) + print_word(mm, ".sp"); + else + print_word(mm, ".PP"); + mm->need_nl = 1; + return(1); +} + +static int +pre_sp(DECL_ARGS) +{ + + mm->need_nl = 1; + print_word(mm, ".sp"); + return(1); +} + +static void +post_sp(DECL_ARGS) +{ + + mm->need_nl = 1; +} + +static int +pre_xr(DECL_ARGS) +{ + + n = n->child; + if (NULL == n) + return(0); + print_node(m, n, mm); + n = n->next; + if (NULL == n) + return(0); + mm->need_space = 0; + print_word(mm, "("); + print_node(m, n, mm); + print_word(mm, ")"); + return(0); +} + +static int +pre_ux(DECL_ARGS) +{ + + print_word(mm, manacts[n->tok].prefix); + if (NULL == n->child) + return(0); + mm->need_space = 0; + print_word(mm, "\\~"); + mm->need_space = 0; + return(1); +} diff --git a/external/bsd/mdocml/dist/mdoc_strings.c b/external/bsd/mdocml/dist/mdoc_strings.c deleted file mode 100644 index d15bb4a85..000000000 --- a/external/bsd/mdocml/dist/mdoc_strings.c +++ /dev/null @@ -1,219 +0,0 @@ -/* $Vendor-Id: mdoc_strings.c,v 1.24 2010/07/31 23:52:58 schwarze Exp $ */ -/* - * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <sys/types.h> - -#include <assert.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <time.h> - -#include "mandoc.h" -#include "libmdoc.h" - -static const char * const secnames[SEC__MAX] = { - NULL, - "NAME", - "LIBRARY", - "SYNOPSIS", - "DESCRIPTION", - "IMPLEMENTATION NOTES", - "RETURN VALUES", - "ENVIRONMENT", - "FILES", - "EXIT STATUS", - "EXAMPLES", - "DIAGNOSTICS", - "COMPATIBILITY", - "ERRORS", - "SEE ALSO", - "STANDARDS", - "HISTORY", - "AUTHORS", - "CAVEATS", - "BUGS", - "SECURITY CONSIDERATIONS", - NULL -}; - -/* - * FIXME: this is repeated in print_text() (html.c) and term_word() - * (term.c). - */ -enum mdelim -mdoc_iscdelim(char p) -{ - - switch (p) { - case('('): - /* FALLTHROUGH */ - case('['): - return(DELIM_OPEN); - case('|'): - return(DELIM_MIDDLE); - case('.'): - /* FALLTHROUGH */ - case(','): - /* FALLTHROUGH */ - case(';'): - /* FALLTHROUGH */ - case(':'): - /* FALLTHROUGH */ - case('?'): - /* FALLTHROUGH */ - case('!'): - /* FALLTHROUGH */ - case(')'): - /* FALLTHROUGH */ - case(']'): - return(DELIM_CLOSE); - default: - break; - } - - return(DELIM_NONE); -} - - -enum mdelim -mdoc_isdelim(const char *p) -{ - - if ('\0' == p[0]) - return(DELIM_NONE); - if ('\0' == p[1]) - return(mdoc_iscdelim(p[0])); - - /* - * XXX; account for groff bubu where the \*(Ba reserved string - * is treated in exactly the same way as the vertical bar. This - * is the only function that checks for this. - */ - return(strcmp(p, "\\*(Ba") ? DELIM_NONE : DELIM_MIDDLE); -} - - -enum mdoc_sec -mdoc_str2sec(const char *p) -{ - int i; - - for (i = 0; i < (int)SEC__MAX; i++) - if (secnames[i] && 0 == strcmp(p, secnames[i])) - return((enum mdoc_sec)i); - - return(SEC_CUSTOM); -} - - -/* FIXME: move this into an editable .in file. */ -size_t -mdoc_macro2len(enum mdoct macro) -{ - - switch (macro) { - case(MDOC_Ad): - return(12); - case(MDOC_Ao): - return(12); - case(MDOC_An): - return(12); - case(MDOC_Aq): - return(12); - case(MDOC_Ar): - return(12); - case(MDOC_Bo): - return(12); - case(MDOC_Bq): - return(12); - case(MDOC_Cd): - return(12); - case(MDOC_Cm): - return(10); - case(MDOC_Do): - return(10); - case(MDOC_Dq): - return(12); - case(MDOC_Dv): - return(12); - case(MDOC_Eo): - return(12); - case(MDOC_Em): - return(10); - case(MDOC_Er): - return(17); - case(MDOC_Ev): - return(15); - case(MDOC_Fa): - return(12); - case(MDOC_Fl): - return(10); - case(MDOC_Fo): - return(16); - case(MDOC_Fn): - return(16); - case(MDOC_Ic): - return(10); - case(MDOC_Li): - return(16); - case(MDOC_Ms): - return(6); - case(MDOC_Nm): - return(10); - case(MDOC_No): - return(12); - case(MDOC_Oo): - return(10); - case(MDOC_Op): - return(14); - case(MDOC_Pa): - return(32); - case(MDOC_Pf): - return(12); - case(MDOC_Po): - return(12); - case(MDOC_Pq): - return(12); - case(MDOC_Ql): - return(16); - case(MDOC_Qo): - return(12); - case(MDOC_So): - return(12); - case(MDOC_Sq): - return(12); - case(MDOC_Sy): - return(6); - case(MDOC_Sx): - return(16); - case(MDOC_Tn): - return(10); - case(MDOC_Va): - return(12); - case(MDOC_Vt): - return(12); - case(MDOC_Xr): - return(10); - default: - break; - }; - return(0); -} diff --git a/external/bsd/mdocml/dist/mdoc_term.c b/external/bsd/mdocml/dist/mdoc_term.c index 38b7e2857..f73276f08 100644 --- a/external/bsd/mdocml/dist/mdoc_term.c +++ b/external/bsd/mdocml/dist/mdoc_term.c @@ -1,6 +1,6 @@ -/* $Vendor-Id: mdoc_term.c,v 1.208 2011/01/06 14:05:12 kristaps Exp $ */ +/* $Vendor-Id: mdoc_term.c,v 1.238 2011/11/13 13:15:14 schwarze Exp $ */ /* - * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any @@ -32,12 +32,8 @@ #include "out.h" #include "term.h" #include "mdoc.h" -#include "chars.h" #include "main.h" -#define INDENT 5 -#define HALFINDENT 3 - struct termpair { struct termpair *ppair; int count; @@ -73,7 +69,6 @@ static void termp_an_post(DECL_ARGS); static void termp_bd_post(DECL_ARGS); static void termp_bk_post(DECL_ARGS); static void termp_bl_post(DECL_ARGS); -static void termp_bx_post(DECL_ARGS); static void termp_d1_post(DECL_ARGS); static void termp_fo_post(DECL_ARGS); static void termp_in_post(DECL_ARGS); @@ -95,6 +90,7 @@ static int termp_bk_pre(DECL_ARGS); static int termp_bl_pre(DECL_ARGS); static int termp_bold_pre(DECL_ARGS); static int termp_bt_pre(DECL_ARGS); +static int termp_bx_pre(DECL_ARGS); static int termp_cd_pre(DECL_ARGS); static int termp_d1_pre(DECL_ARGS); static int termp_ex_pre(DECL_ARGS); @@ -187,7 +183,7 @@ static const struct termact termacts[MDOC_MAX] = { { termp_quote_pre, termp_quote_post }, /* Bo */ { termp_quote_pre, termp_quote_post }, /* Bq */ { termp_xx_pre, NULL }, /* Bsx */ - { NULL, termp_bx_post }, /* Bx */ + { termp_bx_pre, NULL }, /* Bx */ { NULL, NULL }, /* Db */ { NULL, NULL }, /* Dc */ { termp_quote_pre, termp_quote_post }, /* Do */ @@ -195,7 +191,7 @@ static const struct termact termacts[MDOC_MAX] = { { NULL, NULL }, /* Ec */ /* FIXME: no space */ { NULL, NULL }, /* Ef */ { termp_under_pre, NULL }, /* Em */ - { NULL, NULL }, /* Eo */ + { termp_quote_pre, termp_quote_post }, /* Eo */ { termp_xx_pre, NULL }, /* Fx */ { termp_bold_pre, NULL }, /* Ms */ { termp_igndelim_pre, NULL }, /* No */ @@ -260,19 +256,15 @@ terminal_mdoc(void *arg, const struct mdoc *mdoc) p = (struct termp *)arg; + if (0 == p->defindent) + p->defindent = 5; + p->overstep = 0; p->maxrmargin = p->defrmargin; p->tabwidth = term_len(p, 5); if (NULL == p->symtab) - switch (p->enc) { - case (TERMENC_ASCII): - p->symtab = chars_init(CHARS_ASCII); - break; - default: - abort(); - /* NOTREACHED */ - } + p->symtab = mchars_alloc(); n = mdoc_node(mdoc); m = mdoc_meta(mdoc); @@ -312,20 +304,6 @@ print_mdoc_node(DECL_ARGS) memset(&npair, 0, sizeof(struct termpair)); npair.ppair = pair; - - switch (n->type) { - case (MDOC_TEXT): - term_word(p, n->string); - break; - case (MDOC_TBL): - term_tbl(p, n->span); - break; - default: - if (termacts[n->tok].pre && ENDBODY_NOT == n->end) - chld = (*termacts[n->tok].pre) - (p, &npair, m, n); - break; - } /* * Keeps only work until the end of a line. If a keep was @@ -357,6 +335,34 @@ print_mdoc_node(DECL_ARGS) (n->parent && MDOC_SYNPRETTY & n->parent->flags))) p->flags &= ~(TERMP_KEEP | TERMP_PREKEEP); + /* + * After the keep flags have been set up, we may now + * produce output. Note that some pre-handlers do so. + */ + + switch (n->type) { + case (MDOC_TEXT): + if (' ' == *n->string && MDOC_LINE & n->flags) + term_newln(p); + if (MDOC_DELIMC & n->flags) + p->flags |= TERMP_NOSPACE; + term_word(p, n->string); + if (MDOC_DELIMO & n->flags) + p->flags |= TERMP_NOSPACE; + break; + case (MDOC_EQN): + term_eqn(p, n->eqn); + break; + case (MDOC_TBL): + term_tbl(p, n->span); + break; + default: + if (termacts[n->tok].pre && ENDBODY_NOT == n->end) + chld = (*termacts[n->tok].pre) + (p, &npair, m, n); + break; + } + if (chld && n->child) print_mdoc_nodelist(p, &npair, m, n->child); @@ -367,6 +373,8 @@ print_mdoc_node(DECL_ARGS) break; case (MDOC_TBL): break; + case (MDOC_EQN): + break; default: if ( ! termacts[n->tok].post || MDOC_ENDED & n->flags) break; @@ -401,7 +409,6 @@ print_mdoc_node(DECL_ARGS) static void print_mdoc_foot(struct termp *p, const void *arg) { - char buf[DATESIZ], os[BUFSIZ]; const struct mdoc_meta *m; m = (const struct mdoc_meta *)arg; @@ -416,32 +423,29 @@ print_mdoc_foot(struct termp *p, const void *arg) * SYSTEM DATE SYSTEM */ - time2a(m->date, buf, DATESIZ); - strlcpy(os, m->os, BUFSIZ); - term_vspace(p); p->offset = 0; p->rmargin = (p->maxrmargin - - term_strlen(p, buf) + term_len(p, 1)) / 2; + term_strlen(p, m->date) + term_len(p, 1)) / 2; p->flags |= TERMP_NOSPACE | TERMP_NOBREAK; - term_word(p, os); + term_word(p, m->os); term_flushln(p); p->offset = p->rmargin; - p->rmargin = p->maxrmargin - term_strlen(p, os); - p->flags |= TERMP_NOLPAD | TERMP_NOSPACE; + p->rmargin = p->maxrmargin - term_strlen(p, m->os); + p->flags |= TERMP_NOSPACE; - term_word(p, buf); + term_word(p, m->date); term_flushln(p); p->offset = p->rmargin; p->rmargin = p->maxrmargin; p->flags &= ~TERMP_NOBREAK; - p->flags |= TERMP_NOLPAD | TERMP_NOSPACE; + p->flags |= TERMP_NOSPACE; - term_word(p, os); + term_word(p, m->os); term_flushln(p); p->offset = 0; @@ -454,13 +458,11 @@ static void print_mdoc_head(struct termp *p, const void *arg) { char buf[BUFSIZ], title[BUFSIZ]; + size_t buflen, titlen; const struct mdoc_meta *m; m = (const struct mdoc_meta *)arg; - p->rmargin = p->maxrmargin; - p->offset = 0; - /* * The header is strange. It has three components, which are * really two with the first duplicated. It goes like this: @@ -474,8 +476,12 @@ print_mdoc_head(struct termp *p, const void *arg) * switches on the manual section. */ + p->offset = 0; + p->rmargin = p->maxrmargin; + assert(m->vol); strlcpy(buf, m->vol, BUFSIZ); + buflen = term_strlen(p, buf); if (m->arch) { strlcat(buf, " (", BUFSIZ); @@ -484,33 +490,38 @@ print_mdoc_head(struct termp *p, const void *arg) } snprintf(title, BUFSIZ, "%s(%s)", m->title, m->msec); + titlen = term_strlen(p, title); - p->offset = 0; - p->rmargin = (p->maxrmargin - - term_strlen(p, buf) + term_len(p, 1)) / 2; p->flags |= TERMP_NOBREAK | TERMP_NOSPACE; + p->offset = 0; + p->rmargin = 2 * (titlen+1) + buflen < p->maxrmargin ? + (p->maxrmargin - + term_strlen(p, buf) + term_len(p, 1)) / 2 : + p->maxrmargin - buflen; term_word(p, title); term_flushln(p); + p->flags |= TERMP_NOSPACE; p->offset = p->rmargin; - p->rmargin = p->maxrmargin - term_strlen(p, title); - p->flags |= TERMP_NOLPAD | TERMP_NOSPACE; + p->rmargin = p->offset + buflen + titlen < p->maxrmargin ? + p->maxrmargin - titlen : p->maxrmargin; term_word(p, buf); term_flushln(p); - p->offset = p->rmargin; - p->rmargin = p->maxrmargin; p->flags &= ~TERMP_NOBREAK; - p->flags |= TERMP_NOLPAD | TERMP_NOSPACE; - - term_word(p, title); - term_flushln(p); + if (p->rmargin + titlen <= p->maxrmargin) { + p->flags |= TERMP_NOSPACE; + p->offset = p->rmargin; + p->rmargin = p->maxrmargin; + term_word(p, title); + term_flushln(p); + } + p->flags &= ~TERMP_NOSPACE; p->offset = 0; p->rmargin = p->maxrmargin; - p->flags &= ~TERMP_NOSPACE; } @@ -519,9 +530,10 @@ a2height(const struct termp *p, const char *v) { struct roffsu su; + assert(v); if ( ! a2roffsu(v, &su, SCALE_VS)) - SCALE_VS_INIT(&su, term_len(p, 1)); + SCALE_VS_INIT(&su, atoi(v)); return(term_vspan(p, &su)); } @@ -550,9 +562,9 @@ a2offs(const struct termp *p, const char *v) else if (0 == strcmp(v, "left")) return(0); else if (0 == strcmp(v, "indent")) - return(term_len(p, INDENT + 1)); + return(term_len(p, p->defindent + 1)); else if (0 == strcmp(v, "indent-two")) - return(term_len(p, (INDENT + 1) * 2)); + return(term_len(p, (p->defindent + 1) * 2)); else if ( ! a2roffsu(v, &su, SCALE_MAX)) SCALE_HS_INIT(&su, term_strlen(p, v)); @@ -572,6 +584,8 @@ print_bvspace(struct termp *p, { const struct mdoc_node *nn; + assert(n); + term_newln(p); if (MDOC_Bd == bl->tok && bl->norm->Bd.comp) @@ -782,16 +796,11 @@ termp_it_pre(DECL_ARGS) case (LIST_hyphen): if (MDOC_HEAD == n->type) p->flags |= TERMP_NOBREAK; - else - p->flags |= TERMP_NOLPAD; break; case (LIST_hang): if (MDOC_HEAD == n->type) p->flags |= TERMP_NOBREAK; else - p->flags |= TERMP_NOLPAD; - - if (MDOC_HEAD != n->type) break; /* @@ -802,17 +811,14 @@ termp_it_pre(DECL_ARGS) */ if (n->next->child && (MDOC_Bl == n->next->child->tok || - MDOC_Bd == n->next->child->tok)) { + MDOC_Bd == n->next->child->tok)) p->flags &= ~TERMP_NOBREAK; - p->flags &= ~TERMP_NOLPAD; - } else + else p->flags |= TERMP_HANG; break; case (LIST_tag): if (MDOC_HEAD == n->type) p->flags |= TERMP_NOBREAK | TERMP_TWOSPACE; - else - p->flags |= TERMP_NOLPAD; if (MDOC_HEAD != n->type) break; @@ -828,10 +834,6 @@ termp_it_pre(DECL_ARGS) else p->flags |= TERMP_NOBREAK; - assert(n->prev); - if (MDOC_BODY == n->prev->type) - p->flags |= TERMP_NOLPAD; - break; case (LIST_diag): if (MDOC_HEAD == n->type) @@ -988,7 +990,6 @@ termp_it_post(DECL_ARGS) p->flags &= ~TERMP_DANGLE; p->flags &= ~TERMP_NOBREAK; p->flags &= ~TERMP_TWOSPACE; - p->flags &= ~TERMP_NOLPAD; p->flags &= ~TERMP_HANG; } @@ -1004,7 +1005,7 @@ termp_nm_pre(DECL_ARGS) if (MDOC_BODY == n->type) { if (NULL == n->child) return(0); - p->flags |= TERMP_NOLPAD | TERMP_NOSPACE; + p->flags |= TERMP_NOSPACE; p->offset += term_len(p, 1) + (NULL == n->prev->child ? term_strlen(p, m->name) : MDOC_TEXT == n->prev->child->type ? @@ -1049,10 +1050,8 @@ termp_nm_post(DECL_ARGS) if (MDOC_HEAD == n->type && n->next->child) { term_flushln(p); p->flags &= ~(TERMP_NOBREAK | TERMP_HANG); - } else if (MDOC_BODY == n->type && n->child) { + } else if (MDOC_BODY == n->type && n->child) term_flushln(p); - p->flags &= ~TERMP_NOLPAD; - } } @@ -1149,7 +1148,8 @@ static int termp_ns_pre(DECL_ARGS) { - p->flags |= TERMP_NOSPACE; + if ( ! (MDOC_LINE & n->flags)) + p->flags |= TERMP_NOSPACE; return(1); } @@ -1171,25 +1171,30 @@ termp_rs_pre(DECL_ARGS) static int termp_rv_pre(DECL_ARGS) { - const struct mdoc_node *nn; + int nchild; term_newln(p); term_word(p, "The"); - for (nn = n->child; nn; nn = nn->next) { + nchild = n->nchild; + for (n = n->child; n; n = n->next) { term_fontpush(p, TERMFONT_BOLD); - term_word(p, nn->string); + term_word(p, n->string); term_fontpop(p); + p->flags |= TERMP_NOSPACE; - if (nn->next && NULL == nn->next->next) - term_word(p, "(), and"); - else if (nn->next) - term_word(p, "(),"); - else - term_word(p, "()"); + term_word(p, "()"); + + if (nchild > 2 && n->next) { + p->flags |= TERMP_NOSPACE; + term_word(p, ","); + } + + if (n->next && NULL == n->next->next) + term_word(p, "and"); } - if (n->child && n->child->next) + if (nchild > 1) term_word(p, "functions return"); else term_word(p, "function returns"); @@ -1212,31 +1217,34 @@ termp_rv_pre(DECL_ARGS) static int termp_ex_pre(DECL_ARGS) { - const struct mdoc_node *nn; + int nchild; + term_newln(p); term_word(p, "The"); - for (nn = n->child; nn; nn = nn->next) { + nchild = n->nchild; + for (n = n->child; n; n = n->next) { term_fontpush(p, TERMFONT_BOLD); - term_word(p, nn->string); + term_word(p, n->string); term_fontpop(p); - p->flags |= TERMP_NOSPACE; - if (nn->next && NULL == nn->next->next) - term_word(p, ", and"); - else if (nn->next) + + if (nchild > 2 && n->next) { + p->flags |= TERMP_NOSPACE; term_word(p, ","); - else - p->flags &= ~TERMP_NOSPACE; + } + + if (n->next && NULL == n->next->next) + term_word(p, "and"); } - if (n->child && n->child->next) + if (nchild > 1) term_word(p, "utilities exit"); else term_word(p, "utility exits"); term_word(p, "0 on success, and >0 if an error occurs."); - p->flags |= TERMP_SENTENCE; + p->flags |= TERMP_SENTENCE; return(0); } @@ -1276,31 +1284,33 @@ termp_bl_post(DECL_ARGS) term_newln(p); } - /* ARGSUSED */ static int termp_xr_pre(DECL_ARGS) { - const struct mdoc_node *nn; - if (NULL == n->child) + if (NULL == (n = n->child)) return(0); - assert(MDOC_TEXT == n->child->type); - nn = n->child; + assert(MDOC_TEXT == n->type); + term_word(p, n->string); - term_word(p, nn->string); - if (NULL == (nn = nn->next)) + if (NULL == (n = n->next)) return(0); + p->flags |= TERMP_NOSPACE; term_word(p, "("); - term_word(p, nn->string); + p->flags |= TERMP_NOSPACE; + + assert(MDOC_TEXT == n->type); + term_word(p, n->string); + + p->flags |= TERMP_NOSPACE; term_word(p, ")"); return(0); } - /* * This decides how to assert whitespace before any of the SYNOPSIS set * of macros (which, as in the case of Ft/Fo and Ft/Fn, may contain @@ -1414,7 +1424,7 @@ termp_sh_pre(DECL_ARGS) term_fontpush(p, TERMFONT_BOLD); break; case (MDOC_BODY): - p->offset = term_len(p, INDENT); + p->offset = term_len(p, p->defindent); break; default: break; @@ -1482,7 +1492,7 @@ termp_d1_pre(DECL_ARGS) if (MDOC_BLOCK != n->type) return(1); term_newln(p); - p->offset += term_len(p, (INDENT + 1)); + p->offset += term_len(p, p->defindent + 1); return(1); } @@ -1514,30 +1524,43 @@ termp_ft_pre(DECL_ARGS) static int termp_fn_pre(DECL_ARGS) { - const struct mdoc_node *nn; + int pretty; + + pretty = MDOC_SYNPRETTY & n->flags; synopsis_pre(p, n); + if (NULL == (n = n->child)) + return(0); + + assert(MDOC_TEXT == n->type); term_fontpush(p, TERMFONT_BOLD); - term_word(p, n->child->string); + term_word(p, n->string); term_fontpop(p); p->flags |= TERMP_NOSPACE; term_word(p, "("); + p->flags |= TERMP_NOSPACE; - for (nn = n->child->next; nn; nn = nn->next) { + for (n = n->next; n; n = n->next) { + assert(MDOC_TEXT == n->type); term_fontpush(p, TERMFONT_UNDER); - term_word(p, nn->string); + term_word(p, n->string); term_fontpop(p); - if (nn->next) + if (n->next) { + p->flags |= TERMP_NOSPACE; term_word(p, ","); + } } + p->flags |= TERMP_NOSPACE; term_word(p, ")"); - if (MDOC_SYNPRETTY & n->flags) + if (pretty) { + p->flags |= TERMP_NOSPACE; term_word(p, ";"); + } return(0); } @@ -1559,12 +1582,16 @@ termp_fa_pre(DECL_ARGS) term_word(p, nn->string); term_fontpop(p); - if (nn->next) + if (nn->next) { + p->flags |= TERMP_NOSPACE; term_word(p, ","); + } } - if (n->child && n->next && n->next->tok == MDOC_Fa) + if (n->child && n->next && n->next->tok == MDOC_Fa) { + p->flags |= TERMP_NOSPACE; term_word(p, ","); + } return(0); } @@ -1672,13 +1699,27 @@ termp_bd_post(DECL_ARGS) /* ARGSUSED */ -static void -termp_bx_post(DECL_ARGS) +static int +termp_bx_pre(DECL_ARGS) { - if (n->child) + if (NULL != (n = n->child)) { + term_word(p, n->string); p->flags |= TERMP_NOSPACE; - term_word(p, "BSD"); + term_word(p, "BSD"); + } else { + term_word(p, "BSD"); + return(0); + } + + if (NULL != (n = n->next)) { + p->flags |= TERMP_NOSPACE; + term_word(p, "-"); + p->flags |= TERMP_NOSPACE; + term_word(p, n->string); + } + + return(0); } @@ -1687,6 +1728,7 @@ static int termp_xx_pre(DECL_ARGS) { const char *pp; + int flags; pp = NULL; switch (n->tok) { @@ -1712,9 +1754,14 @@ termp_xx_pre(DECL_ARGS) break; } - assert(pp); term_word(p, pp); - return(1); + if (n->child) { + flags = p->flags; + p->flags |= TERMP_KEEP; + term_word(p, n->child->string); + p->flags = flags; + } + return(0); } @@ -1750,7 +1797,7 @@ termp_ss_pre(DECL_ARGS) break; case (MDOC_HEAD): term_fontpush(p, TERMFONT_BOLD); - p->offset = term_len(p, HALFINDENT); + p->offset = term_len(p, (p->defindent+1)/2); break; default: break; @@ -1878,6 +1925,8 @@ termp_quote_pre(DECL_ARGS) case (MDOC_Dq): term_word(p, "``"); break; + case (MDOC_Eo): + break; case (MDOC_Po): /* FALLTHROUGH */ case (MDOC_Pq): @@ -1942,6 +1991,8 @@ termp_quote_post(DECL_ARGS) case (MDOC_Dq): term_word(p, "''"); break; + case (MDOC_Eo): + break; case (MDOC_Po): /* FALLTHROUGH */ case (MDOC_Pq): @@ -1979,6 +2030,7 @@ termp_fo_pre(DECL_ARGS) } else if (MDOC_BODY == n->type) { p->flags |= TERMP_NOSPACE; term_word(p, "("); + p->flags |= TERMP_NOSPACE; return(1); } @@ -2002,10 +2054,13 @@ termp_fo_post(DECL_ARGS) if (MDOC_BODY != n->type) return; + p->flags |= TERMP_NOSPACE; term_word(p, ")"); - if (MDOC_SYNPRETTY & n->flags) + if (MDOC_SYNPRETTY & n->flags) { + p->flags |= TERMP_NOSPACE; term_word(p, ";"); + } } @@ -2079,6 +2134,7 @@ termp____post(DECL_ARGS) if (NULL == n->parent || MDOC_Rs != n->parent->tok) return; + p->flags |= TERMP_NOSPACE; if (NULL == n->next) { term_word(p, "."); p->flags |= TERMP_SENTENCE; @@ -2115,6 +2171,7 @@ termp_lk_pre(DECL_ARGS) term_fontpop(p); + p->flags |= TERMP_NOSPACE; term_word(p, ":"); term_fontpush(p, TERMFONT_BOLD); @@ -2166,8 +2223,8 @@ termp__t_post(DECL_ARGS) * If we're in an `Rs' and there's a journal present, then quote * us instead of underlining us (for disambiguation). */ - if (n->parent && MDOC_Rs == n->parent->tok && - n->parent->norm->Rs.child_J) + if (n->parent && MDOC_Rs == n->parent->tok && + n->parent->norm->Rs.quote_T) termp_quote_post(p, pair, m, n); termp____post(p, pair, m, n); @@ -2183,7 +2240,7 @@ termp__t_pre(DECL_ARGS) * us instead of underlining us (for disambiguation). */ if (n->parent && MDOC_Rs == n->parent->tok && - n->parent->norm->Rs.child_J) + n->parent->norm->Rs.quote_T) return(termp_quote_pre(p, pair, m, n)); term_fontpush(p, TERMFONT_UNDER); diff --git a/external/bsd/mdocml/dist/mdoc_validate.c b/external/bsd/mdocml/dist/mdoc_validate.c index 784b73313..f44fd7b15 100644 --- a/external/bsd/mdocml/dist/mdoc_validate.c +++ b/external/bsd/mdocml/dist/mdoc_validate.c @@ -1,4 +1,4 @@ -/* $Vendor-Id: mdoc_validate.c,v 1.151 2011/01/03 23:53:51 schwarze Exp $ */ +/* $Vendor-Id: mdoc_validate.c,v 1.181 2011/12/03 16:58:54 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org> @@ -33,6 +33,7 @@ #include <string.h> #include <time.h> +#include "mdoc.h" #include "mandoc.h" #include "libmdoc.h" #include "libmandoc.h" @@ -71,14 +72,13 @@ static void check_text(struct mdoc *, int, int, char *); static void check_argv(struct mdoc *, struct mdoc_node *, struct mdoc_argv *); static void check_args(struct mdoc *, struct mdoc_node *); - -static int concat(struct mdoc *, char *, - const struct mdoc_node *, size_t); +static int concat(char *, const struct mdoc_node *, size_t); +static enum mdoc_sec a2sec(const char *); +static size_t macro2len(enum mdoct); static int ebool(POST_ARGS); static int berr_ge1(POST_ARGS); static int bwarn_ge1(POST_ARGS); -static int eerr_ge1(POST_ARGS); static int ewarn_eq0(POST_ARGS); static int ewarn_eq1(POST_ARGS); static int ewarn_ge1(POST_ARGS); @@ -96,6 +96,7 @@ static int post_bl_block(POST_ARGS); static int post_bl_block_width(POST_ARGS); static int post_bl_block_tag(POST_ARGS); static int post_bl_head(POST_ARGS); +static int post_bx(POST_ARGS); static int post_dd(POST_ARGS); static int post_dt(POST_ARGS); static int post_defaults(POST_ARGS); @@ -104,6 +105,7 @@ static int post_eoln(POST_ARGS); static int post_it(POST_ARGS); static int post_lb(POST_ARGS); static int post_nm(POST_ARGS); +static int post_ns(POST_ARGS); static int post_os(POST_ARGS); static int post_ignpar(POST_ARGS); static int post_prol(POST_ARGS); @@ -135,10 +137,11 @@ static v_post posts_bd[] = { post_literal, hwarn_eq0, bwarn_ge1, NULL }; static v_post posts_bf[] = { hwarn_le1, post_bf, NULL }; static v_post posts_bk[] = { hwarn_eq0, bwarn_ge1, NULL }; static v_post posts_bl[] = { bwarn_ge1, post_bl, NULL }; +static v_post posts_bx[] = { post_bx, NULL }; static v_post posts_bool[] = { ebool, NULL }; static v_post posts_eoln[] = { post_eoln, NULL }; static v_post posts_defaults[] = { post_defaults, NULL }; -static v_post posts_dd[] = { ewarn_ge1, post_dd, post_prol, NULL }; +static v_post posts_dd[] = { post_dd, post_prol, NULL }; static v_post posts_dl[] = { post_literal, bwarn_ge1, NULL }; static v_post posts_dt[] = { post_dt, post_prol, NULL }; static v_post posts_fo[] = { hwarn_eq1, bwarn_ge1, NULL }; @@ -147,18 +150,18 @@ static v_post posts_lb[] = { post_lb, NULL }; static v_post posts_nd[] = { berr_ge1, NULL }; static v_post posts_nm[] = { post_nm, NULL }; static v_post posts_notext[] = { ewarn_eq0, NULL }; +static v_post posts_ns[] = { post_ns, NULL }; static v_post posts_os[] = { post_os, post_prol, NULL }; static v_post posts_rs[] = { post_rs, NULL }; -static v_post posts_sh[] = { post_ignpar, hwarn_ge1, bwarn_ge1, post_sh, NULL }; +static v_post posts_sh[] = { post_ignpar, hwarn_ge1, post_sh, NULL }; static v_post posts_sp[] = { ewarn_le1, NULL }; -static v_post posts_ss[] = { post_ignpar, hwarn_ge1, bwarn_ge1, NULL }; +static v_post posts_ss[] = { post_ignpar, hwarn_ge1, NULL }; static v_post posts_st[] = { post_st, NULL }; static v_post posts_std[] = { post_std, NULL }; -static v_post posts_text[] = { eerr_ge1, NULL }; +static v_post posts_text[] = { ewarn_ge1, NULL }; static v_post posts_text1[] = { ewarn_eq1, NULL }; static v_post posts_vt[] = { post_vt, NULL }; static v_post posts_wline[] = { bwarn_ge1, NULL }; -static v_post posts_wtext[] = { ewarn_ge1, NULL }; static v_pre pres_an[] = { pre_an, NULL }; static v_pre pres_bd[] = { pre_display, pre_bd, pre_literal, pre_par, NULL }; static v_pre pres_bl[] = { pre_bl, pre_par, NULL }; @@ -175,7 +178,7 @@ static v_pre pres_sh[] = { pre_sh, NULL }; static v_pre pres_ss[] = { pre_ss, NULL }; static v_pre pres_std[] = { pre_std, NULL }; -const struct valids mdoc_valids[MDOC_MAX] = { +static const struct valids mdoc_valids[MDOC_MAX] = { { NULL, NULL }, /* Ap */ { pres_dd, posts_dd }, /* Dd */ { pres_dt, posts_dt }, /* Dt */ @@ -190,21 +193,21 @@ const struct valids mdoc_valids[MDOC_MAX] = { { pres_bl, posts_bl }, /* Bl */ { NULL, NULL }, /* El */ { pres_it, posts_it }, /* It */ - { NULL, posts_text }, /* Ad */ + { NULL, NULL }, /* Ad */ { pres_an, posts_an }, /* An */ { NULL, posts_defaults }, /* Ar */ - { NULL, posts_text }, /* Cd */ + { NULL, NULL }, /* Cd */ { NULL, NULL }, /* Cm */ { NULL, NULL }, /* Dv */ - { pres_er, posts_text }, /* Er */ + { pres_er, NULL }, /* Er */ { NULL, NULL }, /* Ev */ { pres_std, posts_std }, /* Ex */ { NULL, NULL }, /* Fa */ - { pres_fd, posts_wtext }, /* Fd */ + { pres_fd, posts_text }, /* Fd */ { NULL, NULL }, /* Fl */ - { NULL, posts_text }, /* Fn */ - { NULL, posts_wtext }, /* Ft */ - { NULL, posts_text }, /* Ic */ + { NULL, NULL }, /* Fn */ + { NULL, NULL }, /* Ft */ + { NULL, NULL }, /* Ic */ { NULL, posts_text1 }, /* In */ { NULL, posts_defaults }, /* Li */ { NULL, posts_nd }, /* Nd */ @@ -216,10 +219,10 @@ const struct valids mdoc_valids[MDOC_MAX] = { { NULL, posts_st }, /* St */ { NULL, NULL }, /* Va */ { NULL, posts_vt }, /* Vt */ - { NULL, posts_wtext }, /* Xr */ + { NULL, posts_text }, /* Xr */ { NULL, posts_text }, /* %A */ { NULL, posts_text }, /* %B */ /* FIXME: can be used outside Rs/Re. */ - { NULL, posts_text }, /* %D */ /* FIXME: check date with mandoc_a2time(). */ + { NULL, posts_text }, /* %D */ { NULL, posts_text }, /* %I */ { NULL, posts_text }, /* %J */ { NULL, posts_text }, /* %N */ @@ -237,7 +240,7 @@ const struct valids mdoc_valids[MDOC_MAX] = { { NULL, NULL }, /* Bo */ { NULL, NULL }, /* Bq */ { NULL, NULL }, /* Bsx */ - { NULL, NULL }, /* Bx */ + { NULL, posts_bx }, /* Bx */ { NULL, posts_bool }, /* Db */ { NULL, NULL }, /* Dc */ { NULL, NULL }, /* Do */ @@ -247,9 +250,9 @@ const struct valids mdoc_valids[MDOC_MAX] = { { NULL, NULL }, /* Em */ { NULL, NULL }, /* Eo */ { NULL, NULL }, /* Fx */ - { NULL, posts_text }, /* Ms */ + { NULL, NULL }, /* Ms */ { NULL, posts_notext }, /* No */ - { NULL, posts_notext }, /* Ns */ + { NULL, posts_ns }, /* Ns */ { NULL, NULL }, /* Nx */ { NULL, NULL }, /* Ox */ { NULL, NULL }, /* Pc */ @@ -266,9 +269,9 @@ const struct valids mdoc_valids[MDOC_MAX] = { { NULL, NULL }, /* So */ { NULL, NULL }, /* Sq */ { NULL, posts_bool }, /* Sm */ - { NULL, posts_text }, /* Sx */ - { NULL, posts_text }, /* Sy */ - { NULL, posts_text }, /* Tn */ + { NULL, NULL }, /* Sx */ + { NULL, NULL }, /* Sy */ + { NULL, NULL }, /* Tn */ { NULL, NULL }, /* Ux */ { NULL, NULL }, /* Xc */ { NULL, NULL }, /* Xo */ @@ -284,7 +287,7 @@ const struct valids mdoc_valids[MDOC_MAX] = { { NULL, posts_eoln }, /* Ud */ { NULL, posts_lb }, /* Lb */ { NULL, posts_notext }, /* Lp */ - { NULL, posts_text }, /* Lk */ + { NULL, NULL }, /* Lk */ { NULL, posts_defaults }, /* Mt */ { NULL, NULL }, /* Brq */ { NULL, NULL }, /* Bro */ @@ -319,6 +322,30 @@ static const enum mdoct rsord[RSORD_MAX] = { MDOC__U }; +static const char * const secnames[SEC__MAX] = { + NULL, + "NAME", + "LIBRARY", + "SYNOPSIS", + "DESCRIPTION", + "IMPLEMENTATION NOTES", + "RETURN VALUES", + "ENVIRONMENT", + "FILES", + "EXIT STATUS", + "EXAMPLES", + "DIAGNOSTICS", + "COMPATIBILITY", + "ERRORS", + "SEE ALSO", + "STANDARDS", + "HISTORY", + "AUTHORS", + "CAVEATS", + "BUGS", + "SECURITY CONSIDERATIONS", + NULL +}; int mdoc_valid_pre(struct mdoc *mdoc, struct mdoc_node *n) @@ -336,6 +363,8 @@ mdoc_valid_pre(struct mdoc *mdoc, struct mdoc_node *n) /* FALLTHROUGH */ case (MDOC_TBL): /* FALLTHROUGH */ + case (MDOC_EQN): + /* FALLTHROUGH */ case (MDOC_ROOT): return(1); default: @@ -365,6 +394,8 @@ mdoc_valid_post(struct mdoc *mdoc) switch (mdoc->last->type) { case (MDOC_TEXT): /* FALLTHROUGH */ + case (MDOC_EQN): + /* FALLTHROUGH */ case (MDOC_TBL): return(1); case (MDOC_ROOT): @@ -414,10 +445,10 @@ check_count(struct mdoc *m, enum mdoc_type type, } t = lvl == CHECK_WARN ? MANDOCERR_ARGCWARN : MANDOCERR_ARGCOUNT; - - return(mdoc_vmsg(m, t, m->last->line, m->last->pos, + mandoc_vmsg(t, m->parse, m->last->line, m->last->pos, "want %s%d children (have %d)", - p, val, m->last->nchild)); + p, val, m->last->nchild); + return(1); } static int @@ -433,12 +464,6 @@ bwarn_ge1(POST_ARGS) return(check_count(mdoc, MDOC_BODY, CHECK_WARN, CHECK_GT, 0)); } -static int -eerr_ge1(POST_ARGS) -{ - return(check_count(mdoc, MDOC_ELEM, CHECK_ERROR, CHECK_GT, 0)); -} - static int ewarn_eq0(POST_ARGS) { @@ -518,32 +543,13 @@ check_argv(struct mdoc *m, struct mdoc_node *n, struct mdoc_argv *v) static void check_text(struct mdoc *m, int ln, int pos, char *p) { - int c; - size_t sz; + char *cp; - for ( ; *p; p++, pos++) { - sz = strcspn(p, "\t\\"); - p += (int)sz; + if (MDOC_LITERAL & m->flags) + return; - if ('\0' == *p) - break; - - pos += (int)sz; - - if ('\t' == *p) { - if ( ! (MDOC_LITERAL & m->flags)) - mdoc_pmsg(m, ln, pos, MANDOCERR_BADTAB); - continue; - } - - if (0 == (c = mandoc_special(p))) { - mdoc_pmsg(m, ln, pos, MANDOCERR_BADESCAPE); - continue; - } - - p += c - 1; - pos += c - 1; - } + for (cp = p; NULL != (p = strchr(p, '\t')); p++) + mdoc_pmsg(m, ln, pos + (int)(p - cp), MANDOCERR_BADTAB); } static int @@ -555,10 +561,9 @@ check_parent(PRE_ARGS, enum mdoct tok, enum mdoc_type t) (t == n->parent->type)) return(1); - mdoc_vmsg(mdoc, MANDOCERR_SYNTCHILD, - n->line, n->pos, "want parent %s", - MDOC_ROOT == t ? "<root>" : - mdoc_macronames[tok]); + mandoc_vmsg(MANDOCERR_SYNTCHILD, mdoc->parse, n->line, + n->pos, "want parent %s", MDOC_ROOT == t ? + "<root>" : mdoc_macronames[tok]); return(0); } @@ -697,7 +702,7 @@ pre_bl(PRE_ARGS) if (LIST_column == lt) { n->norm->Bl.ncols = n->args->argv[i].sz; - n->norm->Bl.cols = (const char **) + n->norm->Bl.cols = (void *) n->args->argv[i].value; } } @@ -865,7 +870,7 @@ pre_sh(PRE_ARGS) if (MDOC_BLOCK != n->type) return(1); - mdoc->regs->regs[(int)REG_nS].set = 0; + roff_regunset(mdoc->roff, REG_nS); return(check_parent(mdoc, n, MDOC_MAX, MDOC_ROOT)); } @@ -919,7 +924,7 @@ static int pre_dt(PRE_ARGS) { - if (0 == mdoc->meta.date || mdoc->meta.os) + if (NULL == mdoc->meta.date || mdoc->meta.os) mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO); if (mdoc->meta.title) @@ -932,7 +937,7 @@ static int pre_os(PRE_ARGS) { - if (NULL == mdoc->meta.title || 0 == mdoc->meta.date) + if (NULL == mdoc->meta.title || NULL == mdoc->meta.date) mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO); if (mdoc->meta.os) @@ -1079,12 +1084,11 @@ post_vt(POST_ARGS) /* * The Vt macro comes in both ELEM and BLOCK form, both of which * have different syntaxes (yet more context-sensitive - * behaviour). ELEM types must have a child; BLOCK types, + * behaviour). ELEM types must have a child, which is already + * guaranteed by the in_line parsing routine; BLOCK types, * specifically the BODY, should only have TEXT children. */ - if (MDOC_ELEM == mdoc->last->type) - return(eerr_ge1(mdoc)); if (MDOC_BODY != mdoc->last->type) return(1); @@ -1100,6 +1104,7 @@ static int post_nm(POST_ARGS) { char buf[BUFSIZ]; + int c; /* If no child specified, make sure we have the meta name. */ @@ -1111,11 +1116,14 @@ post_nm(POST_ARGS) /* If no meta name, set it from the child. */ - if ( ! concat(mdoc, buf, mdoc->last->child, BUFSIZ)) + buf[0] = '\0'; + if (-1 == (c = concat(buf, mdoc->last->child, BUFSIZ))) { + mdoc_nmsg(mdoc, mdoc->last->child, MANDOCERR_MEM); return(0); + } + assert(c); mdoc->meta.name = mandoc_strdup(buf); - return(1); } @@ -1228,19 +1236,12 @@ post_an(POST_ARGS) struct mdoc_node *np; np = mdoc->last; - if (AUTH__NONE != np->norm->An.auth && np->child) { + if (AUTH__NONE == np->norm->An.auth) { + if (0 == np->child) + check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_GT, 0); + } else if (np->child) check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 0); - return(1); - } - /* - * FIXME: make this ewarn and make sure that the front-ends - * don't print the arguments. - */ - if (AUTH__NONE != np->norm->An.auth || np->child) - return(1); - - mdoc_nmsg(mdoc, np, MANDOCERR_NOARGS); return(1); } @@ -1248,7 +1249,7 @@ post_an(POST_ARGS) static int post_it(POST_ARGS) { - int i, cols, rc; + int i, cols; enum mdoc_list lt; struct mdoc_node *n, *c; enum mandocerr er; @@ -1314,10 +1315,10 @@ post_it(POST_ARGS) else er = MANDOCERR_SYNTARGCOUNT; - rc = mdoc_vmsg(mdoc, er, - mdoc->last->line, mdoc->last->pos, + mandoc_vmsg(er, mdoc->parse, mdoc->last->line, + mdoc->last->pos, "columns == %d (have %d)", cols, i); - return(rc); + return(MANDOCERR_ARGCOUNT == er); default: break; } @@ -1378,7 +1379,7 @@ post_bl_block_width(POST_ARGS) width = 6; else if (MDOC_MAX == (tok = mdoc_hash_find(n->norm->Bl.width))) return(1); - else if (0 == (width = mdoc_macro2len(tok))) { + else if (0 == (width = macro2len(tok))) { mdoc_nmsg(mdoc, n, MANDOCERR_BADWIDTH); return(1); } @@ -1393,7 +1394,7 @@ post_bl_block_width(POST_ARGS) assert(i < (int)n->args->argc); - snprintf(buf, NUMSIZ, "%zun", width); + snprintf(buf, NUMSIZ, "%un", (unsigned int)width); free(n->args->argv[i].value[0]); n->args->argv[i].value[0] = mandoc_strdup(buf); @@ -1435,7 +1436,7 @@ post_bl_block_tag(POST_ARGS) break; } - if (0 != (ssz = mdoc_macro2len(nn->tok))) + if (0 != (ssz = macro2len(nn->tok))) sz = ssz; break; @@ -1443,7 +1444,7 @@ post_bl_block_tag(POST_ARGS) /* Defaults to ten ens. */ - snprintf(buf, NUMSIZ, "%zun", sz); + snprintf(buf, NUMSIZ, "%un", (unsigned int)sz); /* * We have to dynamically add this to the macro's argument list. @@ -1509,7 +1510,7 @@ post_bl_head(POST_ARGS) assert(0 == np->args->argv[j].sz); /* - * Accomodate for new-style groff column syntax. Shuffle the + * Accommodate for new-style groff column syntax. Shuffle the * child nodes, all of which must be TEXT, as arguments for the * column field. Then, delete the head children. */ @@ -1519,7 +1520,7 @@ post_bl_head(POST_ARGS) ((size_t)mdoc->last->nchild * sizeof(char *)); mdoc->last->norm->Bl.ncols = np->args->argv[j].sz; - mdoc->last->norm->Bl.cols = (const char **)np->args->argv[j].value; + mdoc->last->norm->Bl.cols = (void *)np->args->argv[j].value; for (i = 0, nn = mdoc->last->child; nn; i++) { np->args->argv[j].value[i] = nn->string; @@ -1681,8 +1682,8 @@ post_rs(POST_ARGS) break; if (i < RSORD_MAX) { - if (MDOC__J == rsord[i]) - mdoc->last->norm->Rs.child_J = nn; + if (MDOC__J == rsord[i] || MDOC__B == rsord[i]) + mdoc->last->norm->Rs.quote_T++; next = nn->next; continue; } @@ -1692,6 +1693,14 @@ post_rs(POST_ARGS) mdoc_node_delete(mdoc, nn); } + /* + * Nothing to sort if only invalid nodes were found + * inside the `Rs' body. + */ + + if (NULL == mdoc->last->child) + return(1); + /* * The full `Rs' block needs special handling to order the * sub-elements according to `rsord'. Pick through each element @@ -1757,6 +1766,15 @@ post_rs(POST_ARGS) return(1); } +static int +post_ns(POST_ARGS) +{ + + if (MDOC_LINE & mdoc->last->flags) + mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_IGNNS); + return(1); +} + static int post_sh(POST_ARGS) { @@ -1808,7 +1826,9 @@ static int post_sh_head(POST_ARGS) { char buf[BUFSIZ]; + struct mdoc_node *n; enum mdoc_sec sec; + int c; /* * Process a new section. Sections are either "named" or @@ -1817,10 +1837,13 @@ post_sh_head(POST_ARGS) * manual sections. */ - if ( ! concat(mdoc, buf, mdoc->last->child, BUFSIZ)) + sec = SEC_CUSTOM; + buf[0] = '\0'; + if (-1 == (c = concat(buf, mdoc->last->child, BUFSIZ))) { + mdoc_nmsg(mdoc, mdoc->last->child, MANDOCERR_MEM); return(0); - - sec = mdoc_str2sec(buf); + } else if (1 == c) + sec = a2sec(buf); /* The NAME should be first. */ @@ -1838,6 +1861,20 @@ post_sh_head(POST_ARGS) mdoc->lastsec = sec; + /* + * Set the section attribute for the current HEAD, for its + * parent BLOCK, and for the HEAD children; the latter can + * only be TEXT nodes, so no recursion is needed. + * For other blocks and elements, including .Sh BODY, this is + * done when allocating the node data structures, but for .Sh + * BLOCK and HEAD, the section is still unknown at that time. + */ + + mdoc->last->parent->sec = sec; + mdoc->last->sec = sec; + for (n = mdoc->last->child; n; n = n->next) + n->sec = sec; + /* We don't care about custom sections after this. */ if (SEC_CUSTOM == sec) @@ -1969,25 +2006,28 @@ post_dd(POST_ARGS) { char buf[DATESIZE]; struct mdoc_node *n; + int c; + + if (mdoc->meta.date) + free(mdoc->meta.date); n = mdoc->last; - - if (NULL == n->child) { - mdoc->meta.date = time(NULL); + if (NULL == n->child || '\0' == n->child->string[0]) { + mdoc->meta.date = mandoc_normdate + (mdoc->parse, NULL, n->line, n->pos); return(1); } - if ( ! concat(mdoc, buf, n->child, DATESIZE)) + buf[0] = '\0'; + if (-1 == (c = concat(buf, n->child, DATESIZE))) { + mdoc_nmsg(mdoc, n->child, MANDOCERR_MEM); return(0); - - mdoc->meta.date = mandoc_a2time - (MTIME_MDOCDATE | MTIME_CANONICAL, buf); - - if (0 == mdoc->meta.date) { - mdoc_nmsg(mdoc, n, MANDOCERR_BADDATE); - mdoc->meta.date = time(NULL); } + assert(c); + mdoc->meta.date = mandoc_normdate + (mdoc->parse, buf, n->line, n->pos); + return(1); } @@ -2013,7 +2053,7 @@ post_dt(POST_ARGS) if (NULL != (nn = n->child)) for (p = nn->string; *p; p++) { - if (toupper((u_char)*p) == *p) + if (toupper((unsigned char)*p) == *p) continue; /* @@ -2059,7 +2099,7 @@ post_dt(POST_ARGS) * arch = NULL */ - cp = mdoc_a2msec(nn->string); + cp = mandoc_a2msec(nn->string); if (cp) { mdoc->meta.vol = mandoc_strdup(cp); mdoc->meta.msec = mandoc_strdup(nn->string); @@ -2115,11 +2155,31 @@ post_prol(POST_ARGS) return(1); } +static int +post_bx(POST_ARGS) +{ + struct mdoc_node *n; + + /* + * Make `Bx's second argument always start with an uppercase + * letter. Groff checks if it's an "accepted" term, but we just + * uppercase blindly. + */ + + n = mdoc->last->child; + if (n && NULL != (n = n->next)) + *n->string = (char)toupper + ((unsigned char)*n->string); + + return(1); +} + static int post_os(POST_ARGS) { struct mdoc_node *n; char buf[BUFSIZ]; + int c; #ifndef OSNAME struct utsname utsname; #endif @@ -2136,8 +2196,13 @@ post_os(POST_ARGS) if (mdoc->meta.os) free(mdoc->meta.os); - if ( ! concat(mdoc, buf, n->child, BUFSIZ)) + buf[0] = '\0'; + if (-1 == (c = concat(buf, n->child, BUFSIZ))) { + mdoc_nmsg(mdoc, n->child, MANDOCERR_MEM); return(0); + } + + assert(c); /* XXX: yes, these can all be dynamically-adjusted buffers, but * it's really not worth the extra hackery. @@ -2150,7 +2215,7 @@ post_os(POST_ARGS) return(0); } #else /*!OSNAME */ - if (uname(&utsname)) { + if (-1 == uname(&utsname)) { mdoc_nmsg(mdoc, n, MANDOCERR_UNAME); mdoc->meta.os = mandoc_strdup("UNKNOWN"); return(post_prol(mdoc)); @@ -2204,36 +2269,130 @@ post_std(POST_ARGS) return(1); } +/* + * Concatenate a node, stopping at the first non-text. + * Concatenation is separated by a single whitespace. + * Returns -1 on fatal (string overrun) error, 0 if child nodes were + * encountered, 1 otherwise. + */ static int -concat(struct mdoc *m, char *p, const struct mdoc_node *n, size_t sz) +concat(char *p, const struct mdoc_node *n, size_t sz) { - p[0] = '\0'; - - /* - * Concatenate sibling nodes together. All siblings must be of - * type MDOC_TEXT or an assertion is raised. Concatenation is - * separated by a single whitespace. Returns 0 on fatal (string - * overrun) error. - */ - - for ( ; n; n = n->next) { - assert(MDOC_TEXT == n->type); - - if (strlcat(p, n->string, sz) >= sz) { - mdoc_nmsg(m, n, MANDOCERR_MEM); + for ( ; NULL != n; n = n->next) { + if (MDOC_TEXT != n->type) return(0); - } - - if (NULL == n->next) - continue; - - if (strlcat(p, " ", sz) >= sz) { - mdoc_nmsg(m, n, MANDOCERR_MEM); - return(0); - } + if ('\0' != p[0] && strlcat(p, " ", sz) >= sz) + return(-1); + if (strlcat(p, n->string, sz) >= sz) + return(-1); + concat(p, n->child, sz); } return(1); } +static enum mdoc_sec +a2sec(const char *p) +{ + int i; + + for (i = 0; i < (int)SEC__MAX; i++) + if (secnames[i] && 0 == strcmp(p, secnames[i])) + return((enum mdoc_sec)i); + + return(SEC_CUSTOM); +} + +static size_t +macro2len(enum mdoct macro) +{ + + switch (macro) { + case(MDOC_Ad): + return(12); + case(MDOC_Ao): + return(12); + case(MDOC_An): + return(12); + case(MDOC_Aq): + return(12); + case(MDOC_Ar): + return(12); + case(MDOC_Bo): + return(12); + case(MDOC_Bq): + return(12); + case(MDOC_Cd): + return(12); + case(MDOC_Cm): + return(10); + case(MDOC_Do): + return(10); + case(MDOC_Dq): + return(12); + case(MDOC_Dv): + return(12); + case(MDOC_Eo): + return(12); + case(MDOC_Em): + return(10); + case(MDOC_Er): + return(17); + case(MDOC_Ev): + return(15); + case(MDOC_Fa): + return(12); + case(MDOC_Fl): + return(10); + case(MDOC_Fo): + return(16); + case(MDOC_Fn): + return(16); + case(MDOC_Ic): + return(10); + case(MDOC_Li): + return(16); + case(MDOC_Ms): + return(6); + case(MDOC_Nm): + return(10); + case(MDOC_No): + return(12); + case(MDOC_Oo): + return(10); + case(MDOC_Op): + return(14); + case(MDOC_Pa): + return(32); + case(MDOC_Pf): + return(12); + case(MDOC_Po): + return(12); + case(MDOC_Pq): + return(12); + case(MDOC_Ql): + return(16); + case(MDOC_Qo): + return(12); + case(MDOC_So): + return(12); + case(MDOC_Sq): + return(12); + case(MDOC_Sy): + return(6); + case(MDOC_Sx): + return(16); + case(MDOC_Tn): + return(10); + case(MDOC_Va): + return(12); + case(MDOC_Vt): + return(12); + case(MDOC_Xr): + return(10); + default: + break; + }; + return(0); +} diff --git a/external/bsd/mdocml/dist/msec.c b/external/bsd/mdocml/dist/msec.c index 3e0ad56fd..d5ec1ed5b 100644 --- a/external/bsd/mdocml/dist/msec.c +++ b/external/bsd/mdocml/dist/msec.c @@ -1,4 +1,4 @@ -/* $Vendor-Id: msec.c,v 1.8 2010/05/17 22:11:42 kristaps Exp $ */ +/* $Vendor-Id: msec.c,v 1.10 2011/12/02 01:37:14 schwarze Exp $ */ /* * Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -22,13 +22,13 @@ #include <string.h> #include "mandoc.h" -#include "libmdoc.h" +#include "libmandoc.h" #define LINE(x, y) \ if (0 == strcmp(p, x)) return(y); const char * -mdoc_a2msec(const char *p) +mandoc_a2msec(const char *p) { #include "msec.in" diff --git a/external/bsd/mdocml/dist/msec.in b/external/bsd/mdocml/dist/msec.in index a7f333576..cd3672d24 100644 --- a/external/bsd/mdocml/dist/msec.in +++ b/external/bsd/mdocml/dist/msec.in @@ -22,16 +22,16 @@ * Be sure to escape strings. */ -LINE("1", "NetBSD General Commands Manual") -LINE("2", "NetBSD System Calls Manual") -LINE("3", "NetBSD Library Functions Manual") +LINE("1", "General Commands Manual") +LINE("2", "System Calls Manual") +LINE("3", "Library Functions Manual") LINE("3p", "Perl Library Functions Manual") -LINE("4", "NetBSD Kernel Interfaces Manual") -LINE("5", "NetBSD File Formats Manual") -LINE("6", "NetBSD Games Manual") -LINE("7", "NetBSD Miscellaneous Information Manual") -LINE("8", "NetBSD System Manager\'s Manual") -LINE("9", "NetBSD Kernel Developer\'s Manual") +LINE("4", "Kernel Interfaces Manual") +LINE("5", "File Formats Manual") +LINE("6", "Games Manual") +LINE("7", "Miscellaneous Information Manual") +LINE("8", "System Manager\'s Manual") +LINE("9", "Kernel Developer\'s Manual") LINE("X11", "X11 Developer\'s Manual") LINE("X11R6", "X11 Developer\'s Manual") LINE("unass", "Unassociated") diff --git a/external/bsd/mdocml/dist/out.c b/external/bsd/mdocml/dist/out.c index eb1b78437..a0e99c196 100644 --- a/external/bsd/mdocml/dist/out.c +++ b/external/bsd/mdocml/dist/out.c @@ -1,6 +1,7 @@ -/* $Vendor-Id: out.c,v 1.30 2011/01/05 15:37:23 kristaps Exp $ */ +/* $Vendor-Id: out.c,v 1.43 2011/09/20 23:05:49 schwarze Exp $ */ /* - * Copyright (c) 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -68,7 +69,7 @@ a2roffsu(const char *src, struct roffsu *dst, enum roffscale def) return(0); while (i < BUFSIZ) { - if ( ! isdigit((u_char)*src)) { + if ( ! isdigit((unsigned char)*src)) { if ('.' != *src) break; else if (hasd) @@ -131,242 +132,6 @@ a2roffsu(const char *src, struct roffsu *dst, enum roffscale def) return(1); } - -/* - * Correctly writes the time in nroff form, which differs from standard - * form in that a space isn't printed in lieu of the extra %e field for - * single-digit dates. - */ -void -time2a(time_t t, char *dst, size_t sz) -{ - struct tm tm; - char buf[5]; - char *p; - size_t nsz; - - assert(sz > 1); - localtime_r(&t, &tm); - - p = dst; - nsz = 0; - - dst[0] = '\0'; - - if (0 == (nsz = strftime(p, sz, "%B ", &tm))) - return; - - p += (int)nsz; - sz -= nsz; - - if (0 == strftime(buf, sizeof(buf), "%e, ", &tm)) - return; - - nsz = strlcat(p, buf + (' ' == buf[0] ? 1 : 0), sz); - - if (nsz >= sz) - return; - - p += (int)nsz; - sz -= nsz; - - (void)strftime(p, sz, "%Y", &tm); -} - - -int -a2roffdeco(enum roffdeco *d, const char **word, size_t *sz) -{ - int i, j, lim; - char term, c; - const char *wp; - enum roffdeco dd; - - *d = DECO_NONE; - lim = i = 0; - term = '\0'; - wp = *word; - - switch ((c = wp[i++])) { - case ('('): - *d = DECO_SPECIAL; - lim = 2; - break; - case ('F'): - /* FALLTHROUGH */ - case ('f'): - *d = 'F' == c ? DECO_FFONT : DECO_FONT; - - switch (wp[i++]) { - case ('('): - lim = 2; - break; - case ('['): - term = ']'; - break; - case ('3'): - /* FALLTHROUGH */ - case ('B'): - *d = DECO_BOLD; - return(i); - case ('2'): - /* FALLTHROUGH */ - case ('I'): - *d = DECO_ITALIC; - return(i); - case ('P'): - *d = DECO_PREVIOUS; - return(i); - case ('1'): - /* FALLTHROUGH */ - case ('R'): - *d = DECO_ROMAN; - return(i); - default: - i--; - lim = 1; - break; - } - break; - case ('k'): - /* FALLTHROUGH */ - case ('M'): - /* FALLTHROUGH */ - case ('m'): - /* FALLTHROUGH */ - case ('*'): - if ('*' == c) - *d = DECO_RESERVED; - - switch (wp[i++]) { - case ('('): - lim = 2; - break; - case ('['): - term = ']'; - break; - default: - i--; - lim = 1; - break; - } - break; - case ('h'): - /* FALLTHROUGH */ - case ('v'): - /* FALLTHROUGH */ - case ('s'): - j = 0; - if ('+' == wp[i] || '-' == wp[i]) { - i++; - j = 1; - } - - switch (wp[i++]) { - case ('('): - lim = 2; - break; - case ('['): - term = ']'; - break; - case ('\''): - term = '\''; - break; - case ('0'): - j = 1; - /* FALLTHROUGH */ - default: - i--; - lim = 1; - break; - } - - if ('+' == wp[i] || '-' == wp[i]) { - if (j) - return(i); - i++; - } - - /* Handle embedded numerical subexp or escape. */ - - if ('(' == wp[i]) { - while (wp[i] && ')' != wp[i]) - if ('\\' == wp[i++]) { - /* Handle embedded escape. */ - *word = &wp[i]; - i += a2roffdeco(&dd, word, sz); - } - - if (')' == wp[i++]) - break; - - *d = DECO_NONE; - return(i - 1); - } else if ('\\' == wp[i]) { - *word = &wp[++i]; - i += a2roffdeco(&dd, word, sz); - } - - break; - case ('['): - *d = DECO_SPECIAL; - term = ']'; - break; - case ('c'): - *d = DECO_NOSPACE; - return(i); - case ('z'): - *d = DECO_NONE; - if ('\\' == wp[i]) { - *word = &wp[++i]; - return(i + a2roffdeco(&dd, word, sz)); - } else - lim = 1; - break; - case ('o'): - /* FALLTHROUGH */ - case ('w'): - if ('\'' == wp[i++]) { - term = '\''; - break; - } - /* FALLTHROUGH */ - default: - *d = DECO_SSPECIAL; - i--; - lim = 1; - break; - } - - assert(term || lim); - *word = &wp[i]; - - if (term) { - j = i; - while (wp[i] && wp[i] != term) - i++; - if ('\0' == wp[i]) { - *d = DECO_NONE; - return(i); - } - - assert(i >= j); - *sz = (size_t)(i - j); - - return(i + 1); - } - - assert(lim > 0); - *sz = (size_t)lim; - - for (j = 0; wp[i] && j < lim; j++) - i++; - if (j < lim) - *d = DECO_NONE; - - return(i); -} - /* * Calculate the abstract widths and decimal positions of columns in a * table. This routine allocates the columns structures then runs over @@ -379,6 +144,7 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp) const struct tbl_dat *dp; const struct tbl_head *hp; struct roffcol *col; + int spans; /* * Allocate the master column specifiers. These will hold the @@ -387,20 +153,27 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp) */ assert(NULL == tbl->cols); - tbl->cols = calloc(sp->tbl->cols, sizeof(struct roffcol)); + tbl->cols = mandoc_calloc + ((size_t)sp->tbl->cols, sizeof(struct roffcol)); hp = sp->head; for ( ; sp; sp = sp->next) { if (TBL_SPAN_DATA != sp->pos) continue; + spans = 1; /* * Account for the data cells in the layout, matching it * to data cells in the data section. */ for (dp = sp->first; dp; dp = dp->next) { - if (NULL == dp->layout) + /* Do not used spanned cells in the calculation. */ + if (0 < --spans) continue; + spans = dp->spans; + if (1 < spans) + continue; + assert(dp->layout); col = &tbl->cols[dp->layout->head->ident]; tblcalc_data(tbl, col, sp->tbl, dp); } @@ -454,6 +227,8 @@ tblcalc_data(struct rofftbl *tbl, struct roffcol *col, case (TBL_CELL_NUMBER): tblcalc_number(tbl, col, tp, dp); break; + case (TBL_CELL_DOWN): + break; default: abort(); /* NOTREACHED */ @@ -464,36 +239,12 @@ static void tblcalc_literal(struct rofftbl *tbl, struct roffcol *col, const struct tbl_dat *dp) { - size_t sz, bufsz, spsz; + size_t sz; + const char *str; - /* - * Calculate our width and use the spacing, with a minimum - * spacing dictated by position (centre, e.g,. gets a space on - * either side, while right/left get a single adjacent space). - */ + str = dp->string ? dp->string : ""; + sz = (*tbl->slen)(str, tbl->arg); - sz = bufsz = spsz = 0; - if (dp->string) - sz = (*tbl->slen)(dp->string, tbl->arg); - - assert(dp->layout); - switch (dp->layout->pos) { - case (TBL_CELL_LONG): - /* FALLTHROUGH */ - case (TBL_CELL_CENTRE): - bufsz = (*tbl->len)(2, tbl->arg); - break; - default: - bufsz = (*tbl->len)(1, tbl->arg); - break; - } - - if (dp->layout->spacing) { - spsz = (*tbl->len)(dp->layout->spacing, tbl->arg); - bufsz = bufsz > spsz ? bufsz : spsz; - } - - sz += bufsz; if (col->width < sz) col->width = sz; } @@ -504,33 +255,30 @@ tblcalc_number(struct rofftbl *tbl, struct roffcol *col, { int i; size_t sz, psz, ssz, d; - char *cp; const char *str; + char *cp; char buf[2]; - /* TODO: use spacing modifier. */ - /* * First calculate number width and decimal place (last + 1 for - * no-decimal numbers). If the stored decimal is subsequent + * non-decimal numbers). If the stored decimal is subsequent to * ours, make our size longer by that difference * (right-"shifting"); similarly, if ours is subsequent the * stored, then extend the stored size by the difference. * Finally, re-assign the stored values. */ - str = ""; - if (dp->string) - str = dp->string; - + str = dp->string ? dp->string : ""; sz = (*tbl->slen)(str, tbl->arg); + /* FIXME: TBL_DATA_HORIZ et al.? */ + buf[0] = tp->decimal; buf[1] = '\0'; psz = (*tbl->slen)(buf, tbl->arg); - if (NULL != (cp = strchr(str, tp->decimal))) { + if (NULL != (cp = strrchr(str, tp->decimal))) { buf[1] = '\0'; for (ssz = 0, i = 0; cp != &str[i]; i++) { buf[0] = str[i]; @@ -540,11 +288,6 @@ tblcalc_number(struct rofftbl *tbl, struct roffcol *col, } else d = sz + psz; - /* Padding. */ - - sz += (*tbl->len)(2, tbl->arg); - d += (*tbl->len)(1, tbl->arg); - /* Adjust the settings for this column. */ if (col->decimal > d) { @@ -558,5 +301,3 @@ tblcalc_number(struct rofftbl *tbl, struct roffcol *col, if (d > col->decimal) col->decimal = d; } - - diff --git a/external/bsd/mdocml/dist/out.h b/external/bsd/mdocml/dist/out.h index 4cba1bf5e..dfb665e72 100644 --- a/external/bsd/mdocml/dist/out.h +++ b/external/bsd/mdocml/dist/out.h @@ -1,6 +1,6 @@ -/* $Vendor-Id: out.h,v 1.15 2011/01/05 15:37:23 kristaps Exp $ */ +/* $Vendor-Id: out.h,v 1.21 2011/07/17 15:24:25 kristaps Exp $ */ /* - * Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -17,17 +17,32 @@ #ifndef OUT_H #define OUT_H -#define DATESIZ 24 - -__BEGIN_DECLS +enum roffscale { + SCALE_CM, /* centimeters (c) */ + SCALE_IN, /* inches (i) */ + SCALE_PC, /* pica (P) */ + SCALE_PT, /* points (p) */ + SCALE_EM, /* ems (m) */ + SCALE_MM, /* mini-ems (M) */ + SCALE_EN, /* ens (n) */ + SCALE_BU, /* default horizontal (u) */ + SCALE_VS, /* default vertical (v) */ + SCALE_FS, /* syn. for u (f) */ + SCALE_MAX +}; struct roffcol { size_t width; /* width of cell */ size_t decimal; /* decimal position in cell */ }; -typedef size_t (*tbl_strlen)(const char *, void *); -typedef size_t (*tbl_len)(size_t, void *); +struct roffsu { + enum roffscale unit; + double scale; +}; + +typedef size_t (*tbl_strlen)(const char *, void *); +typedef size_t (*tbl_len)(size_t, void *); struct rofftbl { tbl_strlen slen; /* calculate string length */ @@ -36,39 +51,7 @@ struct rofftbl { void *arg; /* passed to slen and len */ }; -enum roffscale { - SCALE_CM, - SCALE_IN, - SCALE_PC, - SCALE_PT, - SCALE_EM, - SCALE_MM, - SCALE_EN, - SCALE_BU, - SCALE_VS, - SCALE_FS, - SCALE_MAX -}; - -enum roffdeco { - DECO_NONE, - DECO_SPECIAL, /* special character */ - DECO_SSPECIAL, /* single-char special */ - DECO_RESERVED, /* reserved word */ - DECO_BOLD, /* bold font */ - DECO_ITALIC, /* italic font */ - DECO_ROMAN, /* "normal" undecorated font */ - DECO_PREVIOUS, /* revert to previous font */ - DECO_NOSPACE, /* suppress spacing */ - DECO_FONT, /* font */ - DECO_FFONT, /* font family */ - DECO_MAX -}; - -struct roffsu { - enum roffscale unit; - double scale; -}; +__BEGIN_DECLS #define SCALE_VS_INIT(p, v) \ do { (p)->unit = SCALE_VS; \ @@ -80,10 +63,8 @@ struct roffsu { (p)->scale = (v); } \ while (/* CONSTCOND */ 0) -int a2roffsu(const char *, struct roffsu *, enum roffscale); -int a2roffdeco(enum roffdeco *, const char **, size_t *); -void time2a(time_t, char *, size_t); -void tblcalc(struct rofftbl *tbl, const struct tbl_span *); +int a2roffsu(const char *, struct roffsu *, enum roffscale); +void tblcalc(struct rofftbl *tbl, const struct tbl_span *); __END_DECLS diff --git a/external/bsd/mdocml/dist/preconv.1 b/external/bsd/mdocml/dist/preconv.1 new file mode 100644 index 000000000..98bd3da34 --- /dev/null +++ b/external/bsd/mdocml/dist/preconv.1 @@ -0,0 +1,158 @@ +.\" $Vendor-Id: preconv.1,v 1.6 2011/12/25 19:35:44 kristaps Exp $ +.\" +.\" Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv> +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd December 25, 2011 +.Dt PRECONV 1 +.Os +.Sh NAME +.Nm preconv +.Nd recode multibyte UNIX manuals +.Sh SYNOPSIS +.Nm preconv +.Op Fl D Ar enc +.Op Fl e Ar enc +.Op Ar file +.Sh DESCRIPTION +The +.Nm +utility recodes multibyte +.Ux +manual files into +.Xr mandoc 1 +.Po +or other troff system supporting the +.Sq \e[uNNNN] +escape sequence +.Pc +input. +.Pp +By default, it parses from standard output, determining encoding as +described in +.Sx Algorithm . +.Pp +Its arguments are as follows: +.Bl -tag -width Ds +.It Fl D Ar enc +The default encoding. +.It Fl e Ar enc +The document's encoding. +.It Ar file +The input file. +.El +.Pp +The recoded input is written to standard output: Unicode characters in +the ASCII range are printed as regular ASCII characters, while those +above this range are printed using the +.Sq \e[uNNNN] +format documented in +.Xr mandoc_char 7 . +.Pp +If input bytes are improperly formed in the current encoding, they're +passed unmodified to standard output. +For some encodings, such as UTF-8, unrecoverable input sequences will +cause +.Nm +to stop processing and exit. +.Ss Algorithm +An encoding is chosen according to the following steps: +.Bl -enum +.It +From the argument passed to +.Fl e Ar enc . +.It +If a BOM exists, UTF\-8 encoding is selected. +.It +From the coding tags parsed from +.Qq File Variables +on the first two lines of input. +A file variable is an input line of the form +.Pp +.Dl \%.\e\(dq -*- key: val [; key: val ]* -*- +.Pp +A coding tag variable is where +.Cm key +is +.Qq coding +and +.Cm val +is the name of the encoding. +A typical file variable with a coding tag is +.Pp +.Dl \%.\e\(dq -*- mode: troff; coding: utf-8 -*- +.It +From the argument passed to +.Fl D Ar enc . +.It +If all else fails, Latin\-1 is used. +.El +.Pp +The +.Nm +utility recognises the UTF\-8, us\-ascii, and latin\-1 encodings as +passed to the +.Fl e +and +.Fl D +arguments, or as coding tags. +Encodings are matched case-insensitively. +.\" .Sh IMPLEMENTATION NOTES +.\" Not used in OpenBSD. +.\" .Sh RETURN VALUES +.\" For sections 2, 3, & 9 only. +.\" .Sh ENVIRONMENT +.\" For sections 1, 6, 7, & 8 only. +.\" .Sh FILES +.Sh EXIT STATUS +.Ex -std +.Sh EXAMPLES +Explicitly page a UTF\-8 manual +.Pa foo.1 +in the current locale: +.Pp +.Dl $ preconv \-e utf\-8 foo.1 | mandoc -Tlocale | less +.\" .Sh DIAGNOSTICS +.\" For sections 1, 4, 6, 7, & 8 only. +.\" .Sh ERRORS +.\" For sections 2, 3, & 9 only. +.Sh SEE ALSO +.Xr mandoc 1 , +.Xr mandoc_char 7 +.Sh STANDARDS +The +.Nm +utility references the US-ASCII character set standard, ANSI_X3.4\-1968; +the Latin\-1 character set standard, ISO/IEC 8859\-1:1998; the UTF\-8 +character set standard; and UCS (Unicode), ISO/IEC 10646. +.Sh HISTORY +The +.Nm +utility first appeared in the GNU troff +.Pq Dq groff +system in December 2005, authored by Tomohiro Kubota and Werner +Lemberg. +The implementation that is part of the +.Xr mandoc 1 +utility appeared in May 2011. +.Sh AUTHORS +The +.Nm +utility was written by +.An Kristaps Dzonsons , +.Mt kristaps@bsd.lv . +.\" .Sh CAVEATS +.\" .Sh BUGS +.\" .Sh SECURITY CONSIDERATIONS +.\" Not used in OpenBSD. diff --git a/external/bsd/mdocml/dist/preconv.c b/external/bsd/mdocml/dist/preconv.c new file mode 100644 index 000000000..c6afae679 --- /dev/null +++ b/external/bsd/mdocml/dist/preconv.c @@ -0,0 +1,528 @@ +/* $Vendor-Id: preconv.c,v 1.5 2011/07/24 18:15:14 kristaps Exp $ */ +/* + * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_MMAP +#include <sys/stat.h> +#include <sys/mman.h> +#endif + +#include <assert.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +/* + * The read_whole_file() and resize_buf() functions are copied from + * read.c, including all dependency code (MAP_FILE, etc.). + */ + +#ifndef MAP_FILE +#define MAP_FILE 0 +#endif + +enum enc { + ENC_UTF_8, /* UTF-8 */ + ENC_US_ASCII, /* US-ASCII */ + ENC_LATIN_1, /* Latin-1 */ + ENC__MAX +}; + +struct buf { + char *buf; /* binary input buffer */ + size_t sz; /* size of binary buffer */ + size_t offs; /* starting buffer offset */ +}; + +struct encode { + const char *name; + int (*conv)(const struct buf *); +}; + +static int cue_enc(const struct buf *, size_t *, enum enc *); +static int conv_latin_1(const struct buf *); +static int conv_us_ascii(const struct buf *); +static int conv_utf_8(const struct buf *); +static int read_whole_file(const char *, int, + struct buf *, int *); +static void resize_buf(struct buf *, size_t); +static void usage(void); + +static const struct encode encs[ENC__MAX] = { + { "utf-8", conv_utf_8 }, /* ENC_UTF_8 */ + { "us-ascii", conv_us_ascii }, /* ENC_US_ASCII */ + { "latin-1", conv_latin_1 }, /* ENC_LATIN_1 */ +}; + +static const char *progname; + +static void +usage(void) +{ + + fprintf(stderr, "usage: %s " + "[-D enc] " + "[-e ENC] " + "[file]\n", progname); +} + +static int +conv_latin_1(const struct buf *b) +{ + size_t i; + unsigned char cu; + const char *cp; + + cp = b->buf + (int)b->offs; + + /* + * Latin-1 falls into the first 256 code-points of Unicode, so + * there's no need for any sort of translation. Just make the + * 8-bit characters use the Unicode escape. + * Note that binary values 128 < v < 160 are passed through + * unmodified to mandoc. + */ + + for (i = b->offs; i < b->sz; i++) { + cu = (unsigned char)*cp++; + cu < 160U ? putchar(cu) : printf("\\[u%.4X]", cu); + } + + return(1); +} + +static int +conv_us_ascii(const struct buf *b) +{ + + /* + * US-ASCII has no conversion since it falls into the first 128 + * bytes of Unicode. + */ + + fwrite(b->buf, 1, b->sz, stdout); + return(1); +} + +static int +conv_utf_8(const struct buf *b) +{ + int state, be; + unsigned int accum; + size_t i; + unsigned char cu; + const char *cp; + const long one = 1L; + + cp = b->buf + (int)b->offs; + state = 0; + accum = 0U; + be = 0; + + /* Quick test for big-endian value. */ + + if ( ! (*((const char *)(&one)))) + be = 1; + + for (i = b->offs; i < b->sz; i++) { + cu = (unsigned char)*cp++; + if (state) { + if ( ! (cu & 128) || (cu & 64)) { + /* Bad sequence header. */ + return(0); + } + + /* Accept only legitimate bit patterns. */ + + if (cu > 191 || cu < 128) { + /* Bad in-sequence bits. */ + return(0); + } + + accum |= (cu & 63) << --state * 6; + + /* + * Accum is held in little-endian order as + * stipulated by the UTF-8 sequence coding. We + * need to convert to a native big-endian if our + * architecture requires it. + */ + + if (0 == state && be) + accum = (accum >> 24) | + ((accum << 8) & 0x00FF0000) | + ((accum >> 8) & 0x0000FF00) | + (accum << 24); + + if (0 == state) { + accum < 128U ? putchar(accum) : + printf("\\[u%.4X]", accum); + accum = 0U; + } + } else if (cu & (1 << 7)) { + /* + * Entering a UTF-8 state: if we encounter a + * UTF-8 bitmask, calculate the expected UTF-8 + * state from it. + */ + for (state = 0; state < 7; state++) + if ( ! (cu & (1 << (7 - state)))) + break; + + /* Accept only legitimate bit patterns. */ + + switch (state) { + case (4): + if (cu <= 244 && cu >= 240) { + accum = (cu & 7) << 18; + break; + } + /* Bad 4-sequence start bits. */ + return(0); + case (3): + if (cu <= 239 && cu >= 224) { + accum = (cu & 15) << 12; + break; + } + /* Bad 3-sequence start bits. */ + return(0); + case (2): + if (cu <= 223 && cu >= 194) { + accum = (cu & 31) << 6; + break; + } + /* Bad 2-sequence start bits. */ + return(0); + default: + /* Bad sequence bit mask. */ + return(0); + } + state--; + } else + putchar(cu); + } + + if (0 != state) { + /* Bad trailing bits. */ + return(0); + } + + return(1); +} + +static void +resize_buf(struct buf *buf, size_t initial) +{ + + buf->sz = buf->sz > initial / 2 ? + 2 * buf->sz : initial; + + buf->buf = realloc(buf->buf, buf->sz); + if (NULL == buf->buf) { + perror(NULL); + exit(EXIT_FAILURE); + } +} + +static int +read_whole_file(const char *f, int fd, + struct buf *fb, int *with_mmap) +{ + size_t off; + ssize_t ssz; + +#ifdef HAVE_MMAP + struct stat st; + if (-1 == fstat(fd, &st)) { + perror(f); + return(0); + } + + /* + * If we're a regular file, try just reading in the whole entry + * via mmap(). This is faster than reading it into blocks, and + * since each file is only a few bytes to begin with, I'm not + * concerned that this is going to tank any machines. + */ + + if (S_ISREG(st.st_mode) && st.st_size >= (1U << 31)) { + fprintf(stderr, "%s: input too large\n", f); + return(0); + } + + if (S_ISREG(st.st_mode)) { + *with_mmap = 1; + fb->sz = (size_t)st.st_size; + fb->buf = mmap(NULL, fb->sz, PROT_READ, + MAP_FILE|MAP_SHARED, fd, 0); + if (fb->buf != MAP_FAILED) + return(1); + } +#endif + + /* + * If this isn't a regular file (like, say, stdin), then we must + * go the old way and just read things in bit by bit. + */ + + *with_mmap = 0; + off = 0; + fb->sz = 0; + fb->buf = NULL; + for (;;) { + if (off == fb->sz && fb->sz == (1U << 31)) { + fprintf(stderr, "%s: input too large\n", f); + break; + } + + if (off == fb->sz) + resize_buf(fb, 65536); + + ssz = read(fd, fb->buf + (int)off, fb->sz - off); + if (ssz == 0) { + fb->sz = off; + return(1); + } + if (ssz == -1) { + perror(f); + break; + } + off += (size_t)ssz; + } + + free(fb->buf); + fb->buf = NULL; + return(0); +} + +static int +cue_enc(const struct buf *b, size_t *offs, enum enc *enc) +{ + const char *ln, *eoln, *eoph; + size_t sz, phsz, nsz; + int i; + + ln = b->buf + (int)*offs; + sz = b->sz - *offs; + + /* Look for the end-of-line. */ + + if (NULL == (eoln = memchr(ln, '\n', sz))) + return(-1); + + /* Set next-line marker. */ + + *offs = (size_t)((eoln + 1) - b->buf); + + /* Check if we have the correct header/trailer. */ + + if ((sz = (size_t)(eoln - ln)) < 10 || + memcmp(ln, ".\\\" -*-", 7) || + memcmp(eoln - 3, "-*-", 3)) + return(0); + + /* Move after the header and adjust for the trailer. */ + + ln += 7; + sz -= 10; + + while (sz > 0) { + while (sz > 0 && ' ' == *ln) { + ln++; + sz--; + } + if (0 == sz) + break; + + /* Find the end-of-phrase marker (or eoln). */ + + if (NULL == (eoph = memchr(ln, ';', sz))) + eoph = eoln - 3; + else + eoph++; + + /* Only account for the "coding" phrase. */ + + if ((phsz = (size_t)(eoph - ln)) < 7 || + strncasecmp(ln, "coding:", 7)) { + sz -= phsz; + ln += phsz; + continue; + } + + sz -= 7; + ln += 7; + + while (sz > 0 && ' ' == *ln) { + ln++; + sz--; + } + if (0 == sz) + break; + + /* Check us against known encodings. */ + + for (i = 0; i < (int)ENC__MAX; i++) { + nsz = strlen(encs[i].name); + if (phsz < nsz) + continue; + if (strncasecmp(ln, encs[i].name, nsz)) + continue; + + *enc = (enum enc)i; + return(1); + } + + /* Unknown encoding. */ + + *enc = ENC__MAX; + return(1); + } + + return(0); +} + +int +main(int argc, char *argv[]) +{ + int i, ch, map, fd, rc; + struct buf b; + const char *fn; + enum enc enc, def; + unsigned char bom[3] = { 0xEF, 0xBB, 0xBF }; + size_t offs; + extern int optind; + extern char *optarg; + + progname = strrchr(argv[0], '/'); + if (progname == NULL) + progname = argv[0]; + else + ++progname; + + fn = "<stdin>"; + fd = STDIN_FILENO; + rc = EXIT_FAILURE; + enc = def = ENC__MAX; + map = 0; + + memset(&b, 0, sizeof(struct buf)); + + while (-1 != (ch = getopt(argc, argv, "D:e:rdvh"))) + switch (ch) { + case ('D'): + /* FALLTHROUGH */ + case ('e'): + for (i = 0; i < (int)ENC__MAX; i++) { + if (strcasecmp(optarg, encs[i].name)) + continue; + break; + } + if (i < (int)ENC__MAX) { + if ('D' == ch) + def = (enum enc)i; + else + enc = (enum enc)i; + break; + } + + fprintf(stderr, "%s: Bad encoding\n", optarg); + return(EXIT_FAILURE); + case ('r'): + /* FALLTHROUGH */ + case ('d'): + /* FALLTHROUGH */ + case ('v'): + /* Compatibility with GNU preconv. */ + break; + case ('h'): + /* Compatibility with GNU preconv. */ + /* FALLTHROUGH */ + default: + usage(); + return(EXIT_FAILURE); + } + + argc -= optind; + argv += optind; + + /* + * Open and read the first argument on the command-line. + * If we don't have one, we default to stdin. + */ + + if (argc > 0) { + fn = *argv; + fd = open(fn, O_RDONLY, 0); + if (-1 == fd) { + perror(fn); + return(EXIT_FAILURE); + } + } + + if ( ! read_whole_file(fn, fd, &b, &map)) + goto out; + + /* Try to read the UTF-8 BOM. */ + + if (ENC__MAX == enc) + if (b.sz > 3 && 0 == memcmp(b.buf, bom, 3)) { + b.offs = 3; + enc = ENC_UTF_8; + } + + /* Try reading from the "-*-" cue. */ + + if (ENC__MAX == enc) { + offs = b.offs; + ch = cue_enc(&b, &offs, &enc); + if (0 == ch) + ch = cue_enc(&b, &offs, &enc); + } + + /* + * No encoding has been detected. + * Thus, we either fall into our default encoder, if specified, + * or use Latin-1 if all else fails. + */ + + if (ENC__MAX == enc) + enc = ENC__MAX == def ? ENC_LATIN_1 : def; + + if ( ! (*encs[(int)enc].conv)(&b)) { + fprintf(stderr, "%s: Bad encoding\n", fn); + goto out; + } + + rc = EXIT_SUCCESS; +out: +#ifdef HAVE_MMAP + if (map) + munmap(b.buf, b.sz); + else +#endif + free(b.buf); + + if (fd > STDIN_FILENO) + close(fd); + + return(rc); +} diff --git a/external/bsd/mdocml/dist/predefs.in b/external/bsd/mdocml/dist/predefs.in new file mode 100644 index 000000000..74684b7e5 --- /dev/null +++ b/external/bsd/mdocml/dist/predefs.in @@ -0,0 +1,65 @@ +/* $Vendor-Id: predefs.in,v 1.3 2011/07/31 11:36:49 schwarze Exp $ */ +/* + * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * The predefined-string translation tables. Each corresponds to a + * predefined strings from (e.g.) tmac/mdoc/doc-nroff. The left-hand + * side corresponds to the input sequence (\*x, \*(xx and so on). The + * right-hand side is what's produced by libroff. + * + * XXX - C-escape strings! + * XXX - update PREDEF_MAX in roff.c if adding more! + */ + +PREDEF("Am", "&") +PREDEF("Ba", "|") +PREDEF("Ge", "\\(>=") +PREDEF("Gt", ">") +PREDEF("If", "infinity") +PREDEF("Le", "\\(<=") +PREDEF("Lq", "\\(lq") +PREDEF("Lt", "<") +PREDEF("Na", "NaN") +PREDEF("Ne", "\\(!=") +PREDEF("Pi", "pi") +PREDEF("Pm", "\\(+-") +PREDEF("Rq", "\\(rq") +PREDEF("left-bracket", "[") +PREDEF("left-parenthesis", "(") +PREDEF("lp", "(") +PREDEF("left-singlequote", "\\(oq") +PREDEF("q", "\\(dq") +PREDEF("quote-left", "\\(oq") +PREDEF("quote-right", "\\(cq") +PREDEF("R", "\\(rg") +PREDEF("right-bracket", "]") +PREDEF("right-parenthesis", ")") +PREDEF("rp", ")") +PREDEF("right-singlequote", "\\(cq") +PREDEF("Tm", "(Tm)") +PREDEF("Px", "POSIX") +PREDEF("Ai", "ANSI") +PREDEF("\'", "\\\'") +PREDEF("aa", "\\(aa") +PREDEF("ga", "\\(ga") +PREDEF("`", "\\`") +PREDEF("lq", "\\(lq") +PREDEF("rq", "\\(rq") +PREDEF("ua", "\\(ua") +PREDEF("va", "\\(va") +PREDEF("<=", "\\(<=") +PREDEF(">=", "\\(>=") diff --git a/external/bsd/mdocml/dist/read.c b/external/bsd/mdocml/dist/read.c new file mode 100644 index 000000000..11bd5b569 --- /dev/null +++ b/external/bsd/mdocml/dist/read.c @@ -0,0 +1,846 @@ +/* $Vendor-Id: read.c,v 1.28 2012/02/16 20:51:31 joerg Exp $ */ +/* + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_MMAP +# include <sys/stat.h> +# include <sys/mman.h> +#endif + +#include <assert.h> +#include <ctype.h> +#include <fcntl.h> +#include <stdarg.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "mandoc.h" +#include "libmandoc.h" +#include "mdoc.h" +#include "man.h" +#include "main.h" + +#ifndef MAP_FILE +#define MAP_FILE 0 +#endif + +#define REPARSE_LIMIT 1000 + +struct buf { + char *buf; /* binary input buffer */ + size_t sz; /* size of binary buffer */ +}; + +struct mparse { + enum mandoclevel file_status; /* status of current parse */ + enum mandoclevel wlevel; /* ignore messages below this */ + int line; /* line number in the file */ + enum mparset inttype; /* which parser to use */ + struct man *pman; /* persistent man parser */ + struct mdoc *pmdoc; /* persistent mdoc parser */ + struct man *man; /* man parser */ + struct mdoc *mdoc; /* mdoc parser */ + struct roff *roff; /* roff parser (!NULL) */ + int reparse_count; /* finite interp. stack */ + mandocmsg mmsg; /* warning/error message handler */ + void *arg; /* argument to mmsg */ + const char *file; + struct buf *secondary; +}; + +static void resize_buf(struct buf *, size_t); +static void mparse_buf_r(struct mparse *, struct buf, int); +static void mparse_readfd_r(struct mparse *, int, const char *, int); +static void pset(const char *, int, struct mparse *); +static int read_whole_file(const char *, int, struct buf *, int *); +static void mparse_end(struct mparse *); + +static const enum mandocerr mandoclimits[MANDOCLEVEL_MAX] = { + MANDOCERR_OK, + MANDOCERR_WARNING, + MANDOCERR_WARNING, + MANDOCERR_ERROR, + MANDOCERR_FATAL, + MANDOCERR_MAX, + MANDOCERR_MAX +}; + +static const char * const mandocerrs[MANDOCERR_MAX] = { + "ok", + + "generic warning", + + /* related to the prologue */ + "no title in document", + "document title should be all caps", + "unknown manual section", + "date missing, using today's date", + "cannot parse date, using it verbatim", + "prologue macros out of order", + "duplicate prologue macro", + "macro not allowed in prologue", + "macro not allowed in body", + + /* related to document structure */ + ".so is fragile, better use ln(1)", + "NAME section must come first", + "bad NAME section contents", + "manual name not yet set", + "sections out of conventional order", + "duplicate section name", + "section not in conventional manual section", + + /* related to macros and nesting */ + "skipping obsolete macro", + "skipping paragraph macro", + "skipping no-space macro", + "blocks badly nested", + "child violates parent syntax", + "nested displays are not portable", + "already in literal mode", + "line scope broken", + + /* related to missing macro arguments */ + "skipping empty macro", + "argument count wrong", + "missing display type", + "list type must come first", + "tag lists require a width argument", + "missing font type", + "skipping end of block that is not open", + + /* related to bad macro arguments */ + "skipping argument", + "duplicate argument", + "duplicate display type", + "duplicate list type", + "unknown AT&T UNIX version", + "bad Boolean value", + "unknown font", + "unknown standard specifier", + "bad width argument", + + /* related to plain text */ + "blank line in non-literal context", + "tab in non-literal context", + "end of line whitespace", + "bad comment style", + "bad escape sequence", + "unterminated quoted string", + + /* related to equations */ + "unexpected literal in equation", + + "generic error", + + /* related to equations */ + "unexpected equation scope closure", + "equation scope open on exit", + "overlapping equation scopes", + "unexpected end of equation", + "equation syntax error", + + /* related to tables */ + "bad table syntax", + "bad table option", + "bad table layout", + "no table layout cells specified", + "no table data cells specified", + "ignore data in cell", + "data block still open", + "ignoring extra data cells", + + "input stack limit exceeded, infinite loop?", + "skipping bad character", + "escaped character not allowed in a name", + "skipping text before the first section header", + "skipping unknown macro", + "NOT IMPLEMENTED, please use groff: skipping request", + "argument count wrong", + "skipping end of block that is not open", + "missing end of block", + "scope open on exit", + "uname(3) system call failed", + "macro requires line argument(s)", + "macro requires body argument(s)", + "macro requires argument(s)", + "missing list type", + "line argument(s) will be lost", + "body argument(s) will be lost", + + "generic fatal error", + + "not a manual", + "column syntax is inconsistent", + "NOT IMPLEMENTED: .Bd -file", + "argument count wrong, violates syntax", + "child violates parent syntax", + "argument count wrong, violates syntax", + "NOT IMPLEMENTED: .so with absolute path or \"..\"", + "no document body", + "no document prologue", + "static buffer exhausted", +}; + +static const char * const mandoclevels[MANDOCLEVEL_MAX] = { + "SUCCESS", + "RESERVED", + "WARNING", + "ERROR", + "FATAL", + "BADARG", + "SYSERR" +}; + +static void +resize_buf(struct buf *buf, size_t initial) +{ + + buf->sz = buf->sz > initial/2 ? 2 * buf->sz : initial; + buf->buf = mandoc_realloc(buf->buf, buf->sz); +} + +static void +pset(const char *buf, int pos, struct mparse *curp) +{ + int i; + + /* + * Try to intuit which kind of manual parser should be used. If + * passed in by command-line (-man, -mdoc), then use that + * explicitly. If passed as -mandoc, then try to guess from the + * line: either skip dot-lines, use -mdoc when finding `.Dt', or + * default to -man, which is more lenient. + * + * Separate out pmdoc/pman from mdoc/man: the first persists + * through all parsers, while the latter is used per-parse. + */ + + if ('.' == buf[0] || '\'' == buf[0]) { + for (i = 1; buf[i]; i++) + if (' ' != buf[i] && '\t' != buf[i]) + break; + if ('\0' == buf[i]) + return; + } + + switch (curp->inttype) { + case (MPARSE_MDOC): + if (NULL == curp->pmdoc) + curp->pmdoc = mdoc_alloc(curp->roff, curp); + assert(curp->pmdoc); + curp->mdoc = curp->pmdoc; + return; + case (MPARSE_MAN): + if (NULL == curp->pman) + curp->pman = man_alloc(curp->roff, curp); + assert(curp->pman); + curp->man = curp->pman; + return; + default: + break; + } + + if (pos >= 3 && 0 == memcmp(buf, ".Dd", 3)) { + if (NULL == curp->pmdoc) + curp->pmdoc = mdoc_alloc(curp->roff, curp); + assert(curp->pmdoc); + curp->mdoc = curp->pmdoc; + return; + } + + if (NULL == curp->pman) + curp->pman = man_alloc(curp->roff, curp); + assert(curp->pman); + curp->man = curp->pman; +} + +/* + * Main parse routine for an opened file. This is called for each + * opened file and simply loops around the full input file, possibly + * nesting (i.e., with `so'). + */ +static void +mparse_buf_r(struct mparse *curp, struct buf blk, int start) +{ + const struct tbl_span *span; + struct buf ln; + enum rofferr rr; + int i, of, rc; + int pos; /* byte number in the ln buffer */ + int lnn; /* line number in the real file */ + unsigned char c; + + memset(&ln, 0, sizeof(struct buf)); + + lnn = curp->line; + pos = 0; + + for (i = 0; i < (int)blk.sz; ) { + if (0 == pos && '\0' == blk.buf[i]) + break; + + if (start) { + curp->line = lnn; + curp->reparse_count = 0; + } + + while (i < (int)blk.sz && (start || '\0' != blk.buf[i])) { + + /* + * When finding an unescaped newline character, + * leave the character loop to process the line. + * Skip a preceding carriage return, if any. + */ + + if ('\r' == blk.buf[i] && i + 1 < (int)blk.sz && + '\n' == blk.buf[i + 1]) + ++i; + if ('\n' == blk.buf[i]) { + ++i; + ++lnn; + break; + } + + /* + * Warn about bogus characters. If you're using + * non-ASCII encoding, you're screwing your + * readers. Since I'd rather this not happen, + * I'll be helpful and replace these characters + * with "?", so we don't display gibberish. + * Note to manual writers: use special characters. + */ + + c = (unsigned char) blk.buf[i]; + + if ( ! (isascii(c) && + (isgraph(c) || isblank(c)))) { + mandoc_msg(MANDOCERR_BADCHAR, curp, + curp->line, pos, NULL); + i++; + if (pos >= (int)ln.sz) + resize_buf(&ln, 256); + ln.buf[pos++] = '?'; + continue; + } + + /* Trailing backslash = a plain char. */ + + if ('\\' != blk.buf[i] || i + 1 == (int)blk.sz) { + if (pos >= (int)ln.sz) + resize_buf(&ln, 256); + ln.buf[pos++] = blk.buf[i++]; + continue; + } + + /* + * Found escape and at least one other character. + * When it's a newline character, skip it. + * When there is a carriage return in between, + * skip that one as well. + */ + + if ('\r' == blk.buf[i + 1] && i + 2 < (int)blk.sz && + '\n' == blk.buf[i + 2]) + ++i; + if ('\n' == blk.buf[i + 1]) { + i += 2; + ++lnn; + continue; + } + + if ('"' == blk.buf[i + 1] || '#' == blk.buf[i + 1]) { + i += 2; + /* Comment, skip to end of line */ + for (; i < (int)blk.sz; ++i) { + if ('\n' == blk.buf[i]) { + ++i; + ++lnn; + break; + } + } + + /* Backout trailing whitespaces */ + for (; pos > 0; --pos) { + if (ln.buf[pos - 1] != ' ') + break; + if (pos > 2 && ln.buf[pos - 2] == '\\') + break; + } + break; + } + + /* Some other escape sequence, copy & cont. */ + + if (pos + 1 >= (int)ln.sz) + resize_buf(&ln, 256); + + ln.buf[pos++] = blk.buf[i++]; + ln.buf[pos++] = blk.buf[i++]; + } + + if (pos >= (int)ln.sz) + resize_buf(&ln, 256); + + ln.buf[pos] = '\0'; + + /* + * A significant amount of complexity is contained by + * the roff preprocessor. It's line-oriented but can be + * expressed on one line, so we need at times to + * readjust our starting point and re-run it. The roff + * preprocessor can also readjust the buffers with new + * data, so we pass them in wholesale. + */ + + of = 0; + + /* + * Maintain a lookaside buffer of all parsed lines. We + * only do this if mparse_keep() has been invoked (the + * buffer may be accessed with mparse_getkeep()). + */ + + if (curp->secondary) { + curp->secondary->buf = + mandoc_realloc + (curp->secondary->buf, + curp->secondary->sz + pos + 2); + memcpy(curp->secondary->buf + + curp->secondary->sz, + ln.buf, pos); + curp->secondary->sz += pos; + curp->secondary->buf + [curp->secondary->sz] = '\n'; + curp->secondary->sz++; + curp->secondary->buf + [curp->secondary->sz] = '\0'; + } +rerun: + rr = roff_parseln + (curp->roff, curp->line, + &ln.buf, &ln.sz, of, &of); + + switch (rr) { + case (ROFF_REPARSE): + if (REPARSE_LIMIT >= ++curp->reparse_count) + mparse_buf_r(curp, ln, 0); + else + mandoc_msg(MANDOCERR_ROFFLOOP, curp, + curp->line, pos, NULL); + pos = 0; + continue; + case (ROFF_APPEND): + pos = (int)strlen(ln.buf); + continue; + case (ROFF_RERUN): + goto rerun; + case (ROFF_IGN): + pos = 0; + continue; + case (ROFF_ERR): + assert(MANDOCLEVEL_FATAL <= curp->file_status); + break; + case (ROFF_SO): + /* + * We remove `so' clauses from our lookaside + * buffer because we're going to descend into + * the file recursively. + */ + if (curp->secondary) + curp->secondary->sz -= pos + 1; + mparse_readfd_r(curp, -1, ln.buf + of, 1); + if (MANDOCLEVEL_FATAL <= curp->file_status) + break; + pos = 0; + continue; + default: + break; + } + + /* + * If we encounter errors in the recursive parse, make + * sure we don't continue parsing. + */ + + if (MANDOCLEVEL_FATAL <= curp->file_status) + break; + + /* + * If input parsers have not been allocated, do so now. + * We keep these instanced between parsers, but set them + * locally per parse routine since we can use different + * parsers with each one. + */ + + if ( ! (curp->man || curp->mdoc)) + pset(ln.buf + of, pos - of, curp); + + /* + * Lastly, push down into the parsers themselves. One + * of these will have already been set in the pset() + * routine. + * If libroff returns ROFF_TBL, then add it to the + * currently open parse. Since we only get here if + * there does exist data (see tbl_data.c), we're + * guaranteed that something's been allocated. + * Do the same for ROFF_EQN. + */ + + rc = -1; + + if (ROFF_TBL == rr) + while (NULL != (span = roff_span(curp->roff))) { + rc = curp->man ? + man_addspan(curp->man, span) : + mdoc_addspan(curp->mdoc, span); + if (0 == rc) + break; + } + else if (ROFF_EQN == rr) + rc = curp->mdoc ? + mdoc_addeqn(curp->mdoc, + roff_eqn(curp->roff)) : + man_addeqn(curp->man, + roff_eqn(curp->roff)); + else if (curp->man || curp->mdoc) + rc = curp->man ? + man_parseln(curp->man, + curp->line, ln.buf, of) : + mdoc_parseln(curp->mdoc, + curp->line, ln.buf, of); + + if (0 == rc) { + assert(MANDOCLEVEL_FATAL <= curp->file_status); + break; + } + + /* Temporary buffers typically are not full. */ + + if (0 == start && '\0' == blk.buf[i]) + break; + + /* Start the next input line. */ + + pos = 0; + } + + free(ln.buf); +} + +static int +read_whole_file(const char *file, int fd, struct buf *fb, int *with_mmap) +{ + size_t off; + ssize_t ssz; + +#ifdef HAVE_MMAP + struct stat st; + if (-1 == fstat(fd, &st)) { + perror(file); + return(0); + } + + /* + * If we're a regular file, try just reading in the whole entry + * via mmap(). This is faster than reading it into blocks, and + * since each file is only a few bytes to begin with, I'm not + * concerned that this is going to tank any machines. + */ + + if (S_ISREG(st.st_mode)) { + if (st.st_size >= (1U << 31)) { + fprintf(stderr, "%s: input too large\n", file); + return(0); + } + *with_mmap = 1; + fb->sz = (size_t)st.st_size; + fb->buf = mmap(NULL, fb->sz, PROT_READ, + MAP_FILE|MAP_SHARED, fd, 0); + if (fb->buf != MAP_FAILED) + return(1); + } +#endif + + /* + * If this isn't a regular file (like, say, stdin), then we must + * go the old way and just read things in bit by bit. + */ + + *with_mmap = 0; + off = 0; + fb->sz = 0; + fb->buf = NULL; + for (;;) { + if (off == fb->sz) { + if (fb->sz == (1U << 31)) { + fprintf(stderr, "%s: input too large\n", file); + break; + } + resize_buf(fb, 65536); + } + ssz = read(fd, fb->buf + (int)off, fb->sz - off); + if (ssz == 0) { + fb->sz = off; + return(1); + } + if (ssz == -1) { + perror(file); + break; + } + off += (size_t)ssz; + } + + free(fb->buf); + fb->buf = NULL; + return(0); +} + +static void +mparse_end(struct mparse *curp) +{ + + if (MANDOCLEVEL_FATAL <= curp->file_status) + return; + + if (curp->mdoc && ! mdoc_endparse(curp->mdoc)) { + assert(MANDOCLEVEL_FATAL <= curp->file_status); + return; + } + + if (curp->man && ! man_endparse(curp->man)) { + assert(MANDOCLEVEL_FATAL <= curp->file_status); + return; + } + + if ( ! (curp->man || curp->mdoc)) { + mandoc_msg(MANDOCERR_NOTMANUAL, curp, 1, 0, NULL); + curp->file_status = MANDOCLEVEL_FATAL; + return; + } + + roff_endparse(curp->roff); +} + +static void +mparse_parse_buffer(struct mparse *curp, struct buf blk, const char *file, + int re) +{ + const char *svfile; + + /* Line number is per-file. */ + svfile = curp->file; + curp->file = file; + curp->line = 1; + + mparse_buf_r(curp, blk, 1); + + if (0 == re && MANDOCLEVEL_FATAL > curp->file_status) + mparse_end(curp); + + curp->file = svfile; +} + +enum mandoclevel +mparse_readmem(struct mparse *curp, const void *buf, size_t len, + const char *file) +{ + struct buf blk; + + blk.buf = UNCONST(buf); + blk.sz = len; + + mparse_parse_buffer(curp, blk, file, 0); + return(curp->file_status); +} + +static void +mparse_readfd_r(struct mparse *curp, int fd, const char *file, int re) +{ + struct buf blk; + int with_mmap; + + if (-1 == fd) + if (-1 == (fd = open(file, O_RDONLY, 0))) { + perror(file); + curp->file_status = MANDOCLEVEL_SYSERR; + return; + } + /* + * Run for each opened file; may be called more than once for + * each full parse sequence if the opened file is nested (i.e., + * from `so'). Simply sucks in the whole file and moves into + * the parse phase for the file. + */ + + if ( ! read_whole_file(file, fd, &blk, &with_mmap)) { + curp->file_status = MANDOCLEVEL_SYSERR; + return; + } + + mparse_parse_buffer(curp, blk, file, re); + +#ifdef HAVE_MMAP + if (with_mmap) + munmap(blk.buf, blk.sz); + else +#endif + free(blk.buf); + + if (STDIN_FILENO != fd && -1 == close(fd)) + perror(file); +} + +enum mandoclevel +mparse_readfd(struct mparse *curp, int fd, const char *file) +{ + + mparse_readfd_r(curp, fd, file, 0); + return(curp->file_status); +} + +struct mparse * +mparse_alloc(enum mparset inttype, enum mandoclevel wlevel, mandocmsg mmsg, void *arg) +{ + struct mparse *curp; + + assert(wlevel <= MANDOCLEVEL_FATAL); + + curp = mandoc_calloc(1, sizeof(struct mparse)); + + curp->wlevel = wlevel; + curp->mmsg = mmsg; + curp->arg = arg; + curp->inttype = inttype; + + curp->roff = roff_alloc(curp); + return(curp); +} + +void +mparse_reset(struct mparse *curp) +{ + + roff_reset(curp->roff); + + if (curp->mdoc) + mdoc_reset(curp->mdoc); + if (curp->man) + man_reset(curp->man); + if (curp->secondary) + curp->secondary->sz = 0; + + curp->file_status = MANDOCLEVEL_OK; + curp->mdoc = NULL; + curp->man = NULL; +} + +void +mparse_free(struct mparse *curp) +{ + + if (curp->pmdoc) + mdoc_free(curp->pmdoc); + if (curp->pman) + man_free(curp->pman); + if (curp->roff) + roff_free(curp->roff); + if (curp->secondary) + free(curp->secondary->buf); + + free(curp->secondary); + free(curp); +} + +void +mparse_result(struct mparse *curp, struct mdoc **mdoc, struct man **man) +{ + + if (mdoc) + *mdoc = curp->mdoc; + if (man) + *man = curp->man; +} + +void +mandoc_vmsg(enum mandocerr t, struct mparse *m, + int ln, int pos, const char *fmt, ...) +{ + char buf[256]; + va_list ap; + + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf) - 1, fmt, ap); + va_end(ap); + + mandoc_msg(t, m, ln, pos, buf); +} + +void +mandoc_msg(enum mandocerr er, struct mparse *m, + int ln, int col, const char *msg) +{ + enum mandoclevel level; + + level = MANDOCLEVEL_FATAL; + while (er < mandoclimits[level]) + level--; + + if (level < m->wlevel) + return; + + if (m->mmsg) + (*m->mmsg)(er, level, m->file, ln, col, msg); + + if (m->file_status < level) + m->file_status = level; +} + +const char * +mparse_strerror(enum mandocerr er) +{ + + return(mandocerrs[er]); +} + +const char * +mparse_strlevel(enum mandoclevel lvl) +{ + return(mandoclevels[lvl]); +} + +void +mparse_keep(struct mparse *p) +{ + + assert(NULL == p->secondary); + p->secondary = mandoc_calloc(1, sizeof(struct buf)); +} + +const char * +mparse_getkeep(const struct mparse *p) +{ + + assert(p->secondary); + return(p->secondary->sz ? p->secondary->buf : NULL); +} diff --git a/external/bsd/mdocml/dist/roff.3 b/external/bsd/mdocml/dist/roff.3 deleted file mode 100644 index 554fb1938..000000000 --- a/external/bsd/mdocml/dist/roff.3 +++ /dev/null @@ -1,177 +0,0 @@ -.\" $Vendor-Id: roff.3,v 1.10 2011/01/01 16:18:39 kristaps Exp $ -.\" -.\" Copyright (c) 2010 Kristaps Dzonsons <kristaps@bsd.lv> -.\" -.\" Permission to use, copy, modify, and distribute this software for any -.\" purpose with or without fee is hereby granted, provided that the above -.\" copyright notice and this permission notice appear in all copies. -.\" -.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -.\" -.Dd January 1, 2011 -.Dt ROFF 3 -.Os -.Sh NAME -.Nm roff , -.Nm roff_alloc , -.Nm roff_endparse , -.Nm roff_free , -.Nm roff_parseln , -.Nm roff_reset , -.Nm roff_span -.Nd roff macro compiler library -.Sh SYNOPSIS -.In mandoc.h -.In roff.h -.Ft "struct roff *" -.Fo roff_alloc -.Fa "struct regset *regs" -.Fa "void *data" -.Fa "mandocmsg msgs" -.Fc -.Ft void -.Fn roff_endparse "struct roff *roff" -.Ft void -.Fn roff_free "struct roff *roff" -.Ft "enum rofferr" -.Fo roff_parseln -.Fa "struct roff *roff" -.Fa "int line" -.Fa "char **bufp" -.Fa "size_t *bufsz" -.Fa "int pos" -.Fa "int *offs" -.Fc -.Ft void -.Fn roff_reset "struct roff *roff" -.Ft "const struct tbl_span *" -.Fn roff_span "const struct roff *roff" -.Sh DESCRIPTION -The -.Nm -library processes lines of -.Xr roff 7 -input. -.Pp -In general, applications initiate a parsing sequence with -.Fn roff_alloc , -parse each line in a document with -.Fn roff_parseln , -close the parsing session with -.Fn roff_endparse , -and finally free all allocated memory with -.Fn roff_free . -The -.Fn roff_reset -function may be used in order to reset the parser for another input -sequence. -.Pp -The -.Fn roff_parseln -function should be invoked before passing a line into the -.Xr mdoc 3 -or -.Xr man 3 -libraries. -.Pp -See the -.Sx EXAMPLES -section for a full example. -.Sh REFERENCE -This section further defines the -.Sx Types -and -.Sx Functions -available to programmers. -.Ss Types -Functions (see -.Sx Functions ) -may use the following types: -.Bl -ohang -.It Vt "enum rofferr" -Instructions for further processing to the caller of -.Fn roff_parseln . -.It Vt struct roff -An opaque type defined in -.Pa roff.c . -Its values are only used privately within the library. -.It Vt mandocmsg -A function callback type defined in -.Pa mandoc.h . -.El -.Ss Functions -Function descriptions follow: -.Bl -ohang -.It Fn roff_alloc -Allocates a parsing structure. -The -.Fa data -pointer is passed to -.Fa msgs . -Returns NULL on failure. -If non-NULL, the pointer must be freed with -.Fn roff_free . -.It Fn roff_reset -Reset the parser for another parse routine. -After its use, -.Fn roff_parseln -behaves as if invoked for the first time. -.It Fn roff_free -Free all resources of a parser. -The pointer is no longer valid after invocation. -.It Fn roff_parseln -Parse a nil-terminated line of input. -The character array -.Fa bufp -may be modified or reallocated within this function. -In the latter case, -.Fa bufsz -will be modified accordingly. -The -.Fa offs -pointer will be modified if the line start during subsequent processing -of the line is not at the zeroth index. -This line should not contain the trailing newline. -Returns 0 on failure, 1 on success. -.It Fn roff_endparse -Signals that the parse is complete. -.It Fn roff_span -If -.Fn roff_parseln -returned -.Va ROFF_TBL , -return the last parsed table row. -Returns NULL otherwise. -.El -.Sh EXAMPLES -See -.Pa main.c -in the source distribution for an example of usage. -.Sh SEE ALSO -.Xr mandoc 1 , -.Xr man 3 , -.Xr mdoc 3 , -.Xr roff 7 -.Sh AUTHORS -The -.Nm -library was written by -.An Kristaps Dzonsons Aq kristaps@bsd.lv . -.Sh BUGS -The implementation of user-defined strings needs improvement: -.Bl -dash -.It -String values are taken literally and are not interpreted. -.It -Parsing of quoted strings is incomplete. -.It -The stings are stored internally using a singly linked list, -which is fine for small numbers of strings, -but ineffient when handling many strings. -.El diff --git a/external/bsd/mdocml/dist/roff.7 b/external/bsd/mdocml/dist/roff.7 index 34a9fb5bb..5e75178a2 100644 --- a/external/bsd/mdocml/dist/roff.7 +++ b/external/bsd/mdocml/dist/roff.7 @@ -1,7 +1,7 @@ -.\" $Vendor-Id: roff.7,v 1.23 2011/01/04 23:32:21 kristaps Exp $ +.\" $Vendor-Id: roff.7,v 1.37 2011/12/11 00:38:11 schwarze Exp $ .\" -.\" Copyright (c) 2010 Kristaps Dzonsons <kristaps@bsd.lv> -.\" Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org> +.\" Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> +.\" Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org> .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above @@ -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 January 4, 2011 +.Dd December 11, 2011 .Dt ROFF 7 .Os .Sh NAME @@ -25,42 +25,281 @@ The .Nm roff language is a general purpose text formatting language. -In particular, it serves as the basis for the +Since traditional implementations of the .Xr mdoc 7 and .Xr man 7 -manual formatting macro languages. -This manual describes the subset of the +manual formatting languages are based on it, +many real-world manuals use small numbers of .Nm -language accepted by the -.Xr mandoc 1 -utility. -.Pp -Input lines beginning with the control characters -.Sq \&. +requests intermixed with their +.Xr mdoc 7 or -.Sq \(aq -are parsed for requests and macros. -These define the document structure, change the processing state -and manipulate the formatting. -Some requests and macros also produce formatted output, -while others do not. +.Xr man 7 +code. +To properly format such manuals, the +.Xr mandoc 1 +utility supports a tiny subset of +.Nm +requests. +Only these requests supported by +.Xr mandoc 1 +are documented in the present manual, +together with the basic language syntax shared by +.Nm , +.Xr mdoc 7 , +and +.Xr man 7 . +For complete +.Nm +manuals, consult the +.Sx SEE ALSO +section. .Pp -All other input lines provide free-form text to be printed; -the formatting of free-form text depends on the respective -processing context. +Input lines beginning with the control character +.Sq \&. +are parsed for requests and macros. +Such lines are called +.Dq request lines +or +.Dq macro lines , +respectively. +Requests change the processing state and manipulate the formatting; +some macros also define the document structure and produce formatted +output. +The single quote +.Pq Qq \(aq +is accepted as an alternative control character, +treated by +.Xr mandoc 1 +just like +.Ql \&. +.Pp +Lines not beginning with control characters are called +.Dq text lines . +They provide free-form text to be printed; the formatting of the text +depends on the respective processing context. .Sh LANGUAGE SYNTAX .Nm documents may contain only graphable 7-bit ASCII characters, the space character, and, in certain circumstances, the tab character. -To produce other characters in the output, use the escape sequences -documented in the -.Xr mandoc_char 7 -manual. +The back-space character +.Sq \e +indicates the start of an escape sequence for +.Sx Comments , +.Sx Special Characters , +.Sx Predefined Strings , +and +user-defined strings defined using the +.Sx ds +request. +.Ss Comments +Text following an escaped double-quote +.Sq \e\(dq , +whether in a request, macro, or text line, is ignored to the end of the line. +A request line beginning with a control character and comment escape +.Sq \&.\e\(dq +is also ignored. +Furthermore, request lines with only a control character and optional +trailing whitespace are stripped from input. .Pp -All manuals must have -.Ux -line terminators. +Examples: +.Bd -literal -offset indent -compact +\&.\e\(dq This is a comment line. +\&.\e\(dq The next line is ignored: +\&. +\&.Sh EXAMPLES \e\(dq This is a comment, too. +\&example text \e\(dq And so is this. +.Ed +.Ss Special Characters +Special characters are used to encode special glyphs and are rendered +differently across output media. +They may occur in request, macro, and text lines. +Sequences begin with the escape character +.Sq \e +followed by either an open-parenthesis +.Sq \&( +for two-character sequences; an open-bracket +.Sq \&[ +for n-character sequences (terminated at a close-bracket +.Sq \&] ) ; +or a single one character sequence. +.Pp +Examples: +.Bl -tag -width Ds -offset indent -compact +.It Li \e(em +Two-letter em dash escape. +.It Li \ee +One-letter backslash escape. +.El +.Pp +See +.Xr mandoc_char 7 +for a complete list. +.Ss Text Decoration +Terms may be text-decorated using the +.Sq \ef +escape followed by an indicator: B (bold), I (italic), R (regular), or P +(revert to previous mode). +A numerical representation 3, 2, or 1 (bold, italic, and regular, +respectively) may be used instead. +The indicator or numerical representative may be preceded by C +(constant-width), which is ignored. +.Pp +Examples: +.Bl -tag -width Ds -offset indent -compact +.It Li \efBbold\efR +Write in bold, then switch to regular font mode. +.It Li \efIitalic\efP +Write in italic, then return to previous font mode. +.El +.Pp +Text decoration is +.Em not +recommended for +.Xr mdoc 7 , +which encourages semantic annotation. +.Ss Predefined Strings +Predefined strings, like +.Sx Special Characters , +mark special output glyphs. +Predefined strings are escaped with the slash-asterisk, +.Sq \e* : +single-character +.Sq \e*X , +two-character +.Sq \e*(XX , +and N-character +.Sq \e*[N] . +.Pp +Examples: +.Bl -tag -width Ds -offset indent -compact +.It Li \e*(Am +Two-letter ampersand predefined string. +.It Li \e*q +One-letter double-quote predefined string. +.El +.Pp +Predefined strings are not recommended for use, +as they differ across implementations. +Those supported by +.Xr mandoc 1 +are listed in +.Xr mandoc_char 7 . +Manuals using these predefined strings are almost certainly not portable. +.Ss Whitespace +Whitespace consists of the space character. +In text lines, whitespace is preserved within a line. +In request and macro lines, whitespace delimits arguments and is discarded. +.Pp +Unescaped trailing spaces are stripped from text line input unless in a +literal context. +In general, trailing whitespace on any input line is discouraged for +reasons of portability. +In the rare case that a blank character is needed at the end of an +input line, it may be forced by +.Sq \e\ \e& . +.Pp +Literal space characters can be produced in the output +using escape sequences. +In macro lines, they can also be included in arguments using quotation; see +.Sx MACRO SYNTAX +for details. +.Pp +Blank text lines, which may include whitespace, are only permitted +within literal contexts. +If the first character of a text line is a space, that line is printed +with a leading newline. +.Ss Scaling Widths +Many requests and macros support scaled widths for their arguments. +The syntax for a scaled width is +.Sq Li [+-]?[0-9]*.[0-9]*[:unit:] , +where a decimal must be preceded or followed by at least one digit. +Negative numbers, while accepted, are truncated to zero. +.Pp +The following scaling units are accepted: +.Pp +.Bl -tag -width Ds -offset indent -compact +.It c +centimetre +.It i +inch +.It P +pica (~1/6 inch) +.It p +point (~1/72 inch) +.It f +synonym for +.Sq u +.It v +default vertical span +.It m +width of rendered +.Sq m +.Pq em +character +.It n +width of rendered +.Sq n +.Pq en +character +.It u +default horizontal span +.It M +mini-em (~1/100 em) +.El +.Pp +Using anything other than +.Sq m , +.Sq n , +.Sq u , +or +.Sq v +is necessarily non-portable across output media. +See +.Sx COMPATIBILITY . +.Pp +If a scaling unit is not provided, the numerical value is interpreted +under the default rules of +.Sq v +for vertical spaces and +.Sq u +for horizontal ones. +.Pp +Examples: +.Bl -tag -width ".Bl -tag -width 2i" -offset indent -compact +.It Li \&.Bl -tag -width 2i +two-inch tagged list indentation in +.Xr mdoc 7 +.It Li \&.HP 2i +two-inch tagged list indentation in +.Xr man 7 +.It Li \&.sp 2v +two vertical spaces +.El +.Ss Sentence Spacing +Each sentence should terminate at the end of an input line. +By doing this, a formatter will be able to apply the proper amount of +spacing after the end of sentence (unescaped) period, exclamation mark, +or question mark followed by zero or more non-sentence closing +delimiters +.Po +.Sq \&) , +.Sq \&] , +.Sq \&' , +.Sq \&" +.Pc . +.Pp +The proper spacing is also intelligently preserved if a sentence ends at +the boundary of a macro line. +.Pp +Examples: +.Bd -literal -offset indent -compact +Do not end sentences mid-line like this. Instead, +end a sentence like this. +A macro would end like this: +\&.Xr mandoc 1 \&. +.Ed .Sh REQUEST SYNTAX A request or macro line consists of: .Pp @@ -86,11 +325,66 @@ Thus, the following request lines are all equivalent: \&.ig end \&. ig end .Ed +.Sh MACRO SYNTAX +Macros are provided by the +.Xr mdoc 7 +and +.Xr man 7 +languages and can be defined by the +.Sx \&de +request. +When called, they follow the same syntax as requests, except that +macro arguments may optionally be quoted by enclosing them +in double quote characters +.Pq Sq \(dq . +Quoted text, even if it contains whitespace or would cause +a macro invocation when unquoted, is always considered literal text. +Inside quoted text, pairs of double quote characters +.Pq Sq Qq +resolve to single double quote characters. +.Pp +To be recognised as the beginning of a quoted argument, the opening +quote character must be preceded by a space character. +A quoted argument extends to the next double quote character that is not +part of a pair, or to the end of the input line, whichever comes earlier. +Leaving out the terminating double quote character at the end of the line +is discouraged. +For clarity, if more arguments follow on the same input line, +it is recommended to follow the terminating double quote character +by a space character; in case the next character after the terminating +double quote character is anything else, it is regarded as the beginning +of the next, unquoted argument. +.Pp +Both in quoted and unquoted arguments, pairs of backslashes +.Pq Sq \e\e +resolve to single backslashes. +In unquoted arguments, space characters can alternatively be included +by preceding them with a backslash +.Pq Sq \e\~ , +but quoting is usually better for clarity. +.Pp +Examples: +.Bl -tag -width Ds -offset indent -compact +.It Li .Fn strlen \(dqconst char *s\(dq +Group arguments +.Qq const char *s +into one function argument. +If unspecified, +.Qq const , +.Qq char , +and +.Qq *s +would be considered separate arguments. +.It Li .Op \(dqFl a\(dq +Consider +.Qq \&Fl a +as literal text instead of a flag macro. +.El .Sh REQUEST REFERENCE The .Xr mandoc 1 .Nm -parser recognizes the following requests. +parser recognises the following requests. Note that the .Nm language defines many more requests not implemented in @@ -98,7 +392,7 @@ language defines many more requests not implemented in .Ss \&ad Set line adjustment mode. This line-scoped request is intended to have one argument to select -normal, left, right, or center adjustment for subsequent text. +normal, left, right, or centre adjustment for subsequent text. Currently, it is ignored including its arguments, and the number of arguments is not checked. .Ss \&am @@ -174,12 +468,9 @@ The macro can be invoked later using the syntax .Pp .D1 Pf . Ar name Op Ar argument Op Ar argument ... .Pp -Arguments are separated by blank characters and can be quoted -using double-quotes -.Pq Sq \(dq -to allow inclusion of blank characters into arguments. -To include the double-quote character into a quoted argument, -escape it from ending the argument by doubling it. +Regarding argument parsing, see +.Sx MACRO SYNTAX +above. .Pp The line invoking the macro will be replaced in the input stream by the @@ -319,6 +610,15 @@ then false is assumed. The syntax of this request is similar to .Sx \&if except that the conditional is missing. +.Ss \&EN +End an equation block. +See +.Sx \&EQ . +.Ss \&EQ +Begin an equation block. +See +.Xr eqn 7 +for a description of the equation language. .Ss \&hy Set automatic hyphenation mode. This line-scoped request is currently ignored. @@ -414,15 +714,20 @@ than having the request or macro follow as The scope of a conditional is always parsed, but only executed if the conditional evaluates to true. .Pp -Note that text following an -.Sq \&.\e} -escape sequence is discarded. -Furthermore, if an explicit closing sequence +Note that the .Sq \e} -is specified in a free-form line, the entire line is accepted within the -scope of the prior request, not only the text preceding the close, with the +is converted into a zero-width escape sequence if not passed as a +standalone macro +.Sq \&.\e} . +For example, +.Pp +.D1 \&.Fl a \e} b +.Pp +will result in .Sq \e} -collapsing into a zero-width space. +being considered an argument of the +.Sq \&Fl +macro. .Ss \&ig Ignore input. Its syntax can be either @@ -512,6 +817,16 @@ section with the .Cm \&Sh macro will reset this register. .El +.Ss \&ns +Turn on no-space mode. +This line-scoped request is intended to take no arguments. +Currently, it is ignored including its arguments, +and the number of arguments is not checked. +.Ss \&ps +Change point size. +This line-scoped request is intended to take one numerical argument. +Currently, it is ignored including its arguments, +and the number of arguments is not checked. .Ss \&so Include a source file. Its syntax is as follows: @@ -523,18 +838,49 @@ The will be read and its contents processed as input in place of the .Sq \&.so request line. -To avoid inadvertant inclusion of unrelated files, +To avoid inadvertent inclusion of unrelated files, .Xr mandoc 1 only accepts relative paths not containing the strings .Qq ../ and .Qq /.. . +.Pp +This request requires +.Xr man 1 +to change to the right directory before calling +.Xr mandoc 1 , +per convention to the root of the manual tree. +Typical usage looks like: +.Pp +.Dl \&.so man3/Xcursor.3 +.Pp +As the whole concept is rather fragile, the use of +.Sx \&so +is discouraged. +Use +.Xr ln 1 +instead. +.Ss \&ta +Set tab stops. +This line-scoped request can take an arbitrary number of arguments. +Currently, it is ignored including its arguments. .Ss \&tr Output character translation. -This request is intended to have one argument, -consisting of an even number of characters. -Currently, it is ignored including its arguments, -and the number of arguments is not checked. +Its syntax is as follows: +.Pp +.D1 Pf \. Cm \&tr Ar [ab]+ +.Pp +Pairs of +.Ar ab +characters are replaced +.Ar ( a +for +.Ar b ) . +Replacement (or origin) characters may also be character escapes; thus, +.Pp +.Dl tr \e(xx\e(yy +.Pp +replaces all invocations of \e(xx with \e(yy. .Ss \&T& Re-start a table layout, retaining the options of the prior table invocation. @@ -560,6 +906,19 @@ refers to groff version 1.15. .Pp .Bl -dash -compact .It +In mandoc, the +.Sx \&EQ , +.Sx \&TE , +.Sx \&TS , +and +.Sx \&T& , +macros are considered regular macros. +In all other +.Nm +implementations, these are special macros that must be specified without +spacing between the control character (which must be a period) and the +macro name. +.It The .Cm nS register is only compatible with OpenBSD's groff-1.15. @@ -577,6 +936,7 @@ using the next-line syntax. .El .Sh SEE ALSO .Xr mandoc 1 , +.Xr eqn 7 , .Xr man 7 , .Xr mandoc_char 7 , .Xr mdoc 7 , @@ -601,19 +961,29 @@ using the next-line syntax. .%U http://heirloom.sourceforge.net/doctools/troff.pdf .Re .Sh HISTORY -The RUNOFF typesetting system was written in PL/1 for the CTSS -operating system by Jerome ("Jerry") E. Saltzer in 1961. -It was first used as the main documentation tool by Multics since 1963. -Robert ("Bob") H. Morris ported it to the GE-635 and called it +The RUNOFF typesetting system, whose input forms the basis for .Nm , -Doug McIlroy rewrote it in BCPL in 1969, -Joseph F. Ossanna rewrote it in PDP-11 assembly in 1973, -and Brian W. Kernighan rewrote it in C in 1975. +was written in MAD and FAP for the CTSS operating system by Jerome E. +Saltzer in 1964. +Doug McIlroy rewrote it in BCPL in 1969, renaming it +.Nm . +Dennis M. Ritchie rewrote McIlroy's +.Nm +in PDP-11 assembly for +.At v1 , +Joseph F. Ossanna improved roff and renamed it nroff +for +.At v2 , +then ported nroff to C as troff, which Brian W. Kernighan released with +.At v7 . +In 1989, James Clarke re-implemented troff in C++, naming it groff. .Sh AUTHORS .An -nosplit -This partial +This .Nm reference was written by -.An Kristaps Dzonsons Aq kristaps@bsd.lv +.An Kristaps Dzonsons , +.Mt kristaps@bsd.lv ; and -.An Ingo Schwarze Aq schwarze@openbsd.org . +.An Ingo Schwarze , +.Mt schwarze@openbsd.org . diff --git a/external/bsd/mdocml/dist/roff.c b/external/bsd/mdocml/dist/roff.c index f70cfa3a1..565ff5b12 100644 --- a/external/bsd/mdocml/dist/roff.c +++ b/external/bsd/mdocml/dist/roff.c @@ -1,4 +1,4 @@ -/* $Vendor-Id: roff.c,v 1.120 2011/01/03 23:24:16 schwarze Exp $ */ +/* $Vendor-Id: roff.c,v 1.172 2011/10/24 21:41:45 schwarze Exp $ */ /* * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org> @@ -20,22 +20,19 @@ #endif #include <assert.h> -#include <errno.h> #include <ctype.h> -#include <limits.h> #include <stdlib.h> #include <string.h> -#include <stdio.h> #include "mandoc.h" -#include "roff.h" #include "libroff.h" #include "libmandoc.h" +/* Maximum number of nested if-else conditionals. */ #define RSTACK_MAX 128 -#define ROFF_CTL(c) \ - ('.' == (c) || '\'' == (c)) +/* Maximum number of string expansions per line, to break infinite loops. */ +#define EXPAND_LIMIT 1000 enum rofft { ROFF_ad, @@ -51,17 +48,23 @@ enum rofft { ROFF_ie, ROFF_if, ROFF_ig, + ROFF_it, ROFF_ne, ROFF_nh, ROFF_nr, + ROFF_ns, + ROFF_ps, ROFF_rm, ROFF_so, + ROFF_ta, ROFF_tr, ROFF_TS, ROFF_TE, ROFF_T_, + ROFF_EQ, + ROFF_EN, ROFF_cblock, - ROFF_ccond, /* FIXME: remove this. */ + ROFF_ccond, ROFF_USERDEF, ROFF_MAX }; @@ -71,24 +74,49 @@ enum roffrule { ROFFRULE_DENY }; +/* + * A single register entity. If "set" is zero, the value of the + * register should be the default one, which is per-register. + * Registers are assumed to be unsigned ints for now. + */ +struct reg { + int set; /* whether set or not */ + unsigned int u; /* unsigned integer */ +}; + +/* + * An incredibly-simple string buffer. + */ struct roffstr { - char *name; /* key of symbol */ - char *string; /* current value */ - struct roffstr *next; /* next in list */ + char *p; /* nil-terminated buffer */ + size_t sz; /* saved strlen(p) */ +}; + +/* + * A key-value roffstr pair as part of a singly-linked list. + */ +struct roffkv { + struct roffstr key; + struct roffstr val; + struct roffkv *next; /* next in list */ }; struct roff { + struct mparse *parse; /* parse point */ struct roffnode *last; /* leaf of stack */ - mandocmsg msg; /* err/warn/fatal messages */ - void *data; /* privdata for messages */ enum roffrule rstack[RSTACK_MAX]; /* stack of !`ie' rules */ int rstackpos; /* position in rstack */ - struct regset *regs; /* read/writable registers */ - struct roffstr *first_string; /* user-defined strings & macros */ + struct reg regs[REG__MAX]; + struct roffkv *strtab; /* user-defined strings & macros */ + struct roffkv *xmbtab; /* multi-byte trans table (`tr') */ + struct roffstr *xtab; /* single-byte trans table (`tr') */ const char *current_string; /* value of last called user macro */ struct tbl_node *first_tbl; /* first table parsed */ struct tbl_node *last_tbl; /* last table parsed */ struct tbl_node *tbl; /* current table being parsed */ + struct eqn_node *last_eqn; /* last equation parsed */ + struct eqn_node *first_eqn; /* first equation parsed */ + struct eqn_node *eqn; /* current equation being parsed */ }; struct roffnode { @@ -123,6 +151,20 @@ struct roffmac { struct roffmac *next; }; +struct predef { + const char *name; /* predefined input name */ + const char *str; /* replacement symbol */ +}; + +#define PREDEF(__name, __str) \ + { (__name), (__str) }, + +static enum rofft roffhash_find(const char *, size_t); +static void roffhash_init(void); +static void roffnode_cleanscope(struct roff *); +static void roffnode_pop(struct roff *); +static void roffnode_push(struct roff *, enum rofft, + const char *, int, int); static enum rofferr roff_block(ROFF_ARGS); static enum rofferr roff_block_text(ROFF_ARGS); static enum rofferr roff_block_sub(ROFF_ARGS); @@ -133,23 +175,34 @@ static enum rofferr roff_cond_text(ROFF_ARGS); static enum rofferr roff_cond_sub(ROFF_ARGS); static enum rofferr roff_ds(ROFF_ARGS); static enum roffrule roff_evalcond(const char *, int *); -static void roff_freestr(struct roff *); +static void roff_free1(struct roff *); +static void roff_freestr(struct roffkv *); +static char *roff_getname(struct roff *, char **, int, int); static const char *roff_getstrn(const struct roff *, const char *, size_t); static enum rofferr roff_line_ignore(ROFF_ARGS); -static enum rofferr roff_line_error(ROFF_ARGS); static enum rofferr roff_nr(ROFF_ARGS); -static int roff_res(struct roff *, - char **, size_t *, int); +static void roff_openeqn(struct roff *, const char *, + int, int, const char *); +static enum rofft roff_parse(struct roff *, const char *, int *); +static enum rofferr roff_parsetext(char *); +static enum rofferr roff_res(struct roff *, + char **, size_t *, int, int); +static enum rofferr roff_rm(ROFF_ARGS); static void roff_setstr(struct roff *, const char *, const char *, int); +static void roff_setstrn(struct roffkv **, const char *, + size_t, const char *, size_t, int); static enum rofferr roff_so(ROFF_ARGS); +static enum rofferr roff_tr(ROFF_ARGS); static enum rofferr roff_TE(ROFF_ARGS); static enum rofferr roff_TS(ROFF_ARGS); +static enum rofferr roff_EQ(ROFF_ARGS); +static enum rofferr roff_EN(ROFF_ARGS); static enum rofferr roff_T_(ROFF_ARGS); static enum rofferr roff_userdef(ROFF_ARGS); -/* See roff_hash_find() */ +/* See roffhash_find() */ #define ASCII_HI 126 #define ASCII_LO 33 @@ -171,35 +224,37 @@ static struct roffmac roffs[ROFF_MAX] = { { "ie", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL }, { "if", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL }, { "ig", roff_block, roff_block_text, roff_block_sub, 0, NULL }, + { "it", roff_line_ignore, NULL, NULL, 0, NULL }, { "ne", roff_line_ignore, NULL, NULL, 0, NULL }, { "nh", roff_line_ignore, NULL, NULL, 0, NULL }, { "nr", roff_nr, NULL, NULL, 0, NULL }, - { "rm", roff_line_error, NULL, NULL, 0, NULL }, + { "ns", roff_line_ignore, NULL, NULL, 0, NULL }, + { "ps", roff_line_ignore, NULL, NULL, 0, NULL }, + { "rm", roff_rm, NULL, NULL, 0, NULL }, { "so", roff_so, NULL, NULL, 0, NULL }, - { "tr", roff_line_ignore, NULL, NULL, 0, NULL }, + { "ta", roff_line_ignore, NULL, NULL, 0, NULL }, + { "tr", roff_tr, NULL, NULL, 0, NULL }, { "TS", roff_TS, NULL, NULL, 0, NULL }, { "TE", roff_TE, NULL, NULL, 0, NULL }, { "T&", roff_T_, NULL, NULL, 0, NULL }, + { "EQ", roff_EQ, NULL, NULL, 0, NULL }, + { "EN", roff_EN, NULL, NULL, 0, NULL }, { ".", roff_cblock, NULL, NULL, 0, NULL }, { "\\}", roff_ccond, NULL, NULL, 0, NULL }, { NULL, roff_userdef, NULL, NULL, 0, NULL }, }; -static void roff_free1(struct roff *); -static enum rofft roff_hash_find(const char *, size_t); -static void roff_hash_init(void); -static void roffnode_cleanscope(struct roff *); -static void roffnode_push(struct roff *, enum rofft, - const char *, int, int); -static void roffnode_pop(struct roff *); -static enum rofft roff_parse(struct roff *, const char *, int *); -static int roff_parse_nat(const char *, unsigned int *); +/* Array of injected predefined strings. */ +#define PREDEFS_MAX 38 +static const struct predef predefs[PREDEFS_MAX] = { +#include "predefs.in" +}; -/* See roff_hash_find() */ +/* See roffhash_find() */ #define ROFF_HASH(p) (p[0] - ASCII_LO) static void -roff_hash_init(void) +roffhash_init(void) { struct roffmac *n; int buc, i; @@ -219,13 +274,12 @@ roff_hash_init(void) } } - /* * Look up a roff token by its name. Returns ROFF_MAX if no macro by * the nil-terminated string name could be found. */ static enum rofft -roff_hash_find(const char *p, size_t s) +roffhash_find(const char *p, size_t s) { int buc; struct roffmac *n; @@ -264,10 +318,6 @@ roffnode_pop(struct roff *r) assert(r->last); p = r->last; - if (ROFF_el == p->tok) - if (r->rstackpos > -1) - r->rstackpos--; - r->last = r->last->parent; free(p->name); free(p->end); @@ -302,27 +352,50 @@ static void roff_free1(struct roff *r) { struct tbl_node *t; + struct eqn_node *e; + int i; - while (r->first_tbl) { - t = r->first_tbl; + while (NULL != (t = r->first_tbl)) { r->first_tbl = t->next; tbl_free(t); } r->first_tbl = r->last_tbl = r->tbl = NULL; + while (NULL != (e = r->first_eqn)) { + r->first_eqn = e->next; + eqn_free(e); + } + + r->first_eqn = r->last_eqn = r->eqn = NULL; + while (r->last) roffnode_pop(r); - roff_freestr(r); -} + roff_freestr(r->strtab); + roff_freestr(r->xmbtab); + r->strtab = r->xmbtab = NULL; + + if (r->xtab) + for (i = 0; i < 128; i++) + free(r->xtab[i].p); + + free(r->xtab); + r->xtab = NULL; +} void roff_reset(struct roff *r) { + int i; roff_free1(r); + + memset(&r->regs, 0, sizeof(struct reg) * REG__MAX); + + for (i = 0; i < PREDEFS_MAX; i++) + roff_setstr(r, predefs[i].name, predefs[i].str, 0); } @@ -336,39 +409,44 @@ roff_free(struct roff *r) struct roff * -roff_alloc(struct regset *regs, void *data, const mandocmsg msg) +roff_alloc(struct mparse *parse) { struct roff *r; + int i; r = mandoc_calloc(1, sizeof(struct roff)); - r->regs = regs; - r->msg = msg; - r->data = data; + r->parse = parse; r->rstackpos = -1; - roff_hash_init(); + roffhash_init(); + + for (i = 0; i < PREDEFS_MAX; i++) + roff_setstr(r, predefs[i].name, predefs[i].str, 0); + return(r); } - /* * Pre-filter each and every line for reserved words (one beginning with * `\*', e.g., `\*(ab'). These must be handled before the actual line * is processed. + * This also checks the syntax of regular escapes. */ -static int -roff_res(struct roff *r, char **bufp, size_t *szp, int pos) +static enum rofferr +roff_res(struct roff *r, char **bufp, size_t *szp, int ln, int pos) { + enum mandoc_esc esc; const char *stesc; /* start of an escape sequence ('\\') */ const char *stnam; /* start of the name, after "[(*" */ const char *cp; /* end of the name, e.g. before ']' */ const char *res; /* the string to be substituted */ - int i, maxl; + int i, maxl, expand_count; size_t nsz; char *n; - /* Search for a leading backslash and save a pointer to it. */ + expand_count = 0; +again: cp = *bufp + pos; while (NULL != (cp = strchr(cp, '\\'))) { stesc = cp++; @@ -380,9 +458,21 @@ roff_res(struct roff *r, char **bufp, size_t *szp, int pos) */ if ('\0' == *cp) - return(1); - if ('*' != *cp++) - continue; + return(ROFF_CONT); + + if ('*' != *cp) { + res = cp; + esc = mandoc_escape(&cp, NULL, NULL); + if (ESCAPE_ERROR != esc) + continue; + cp = res; + mandoc_msg + (MANDOCERR_BADESCAPE, r->parse, + ln, (int)(stesc - *bufp), NULL); + return(ROFF_CONT); + } + + cp++; /* * The third character decides the length @@ -392,7 +482,7 @@ roff_res(struct roff *r, char **bufp, size_t *szp, int pos) switch (*cp) { case ('\0'): - return(1); + return(ROFF_CONT); case ('('): cp++; maxl = 2; @@ -410,8 +500,13 @@ roff_res(struct roff *r, char **bufp, size_t *szp, int pos) /* Advance to the end of the name. */ for (i = 0; 0 == maxl || i < maxl; i++, cp++) { - if ('\0' == *cp) - return(1); /* Error. */ + if ('\0' == *cp) { + mandoc_msg + (MANDOCERR_BADESCAPE, + r->parse, ln, + (int)(stesc - *bufp), NULL); + return(ROFF_CONT); + } if (0 == maxl && ']' == *cp) break; } @@ -424,12 +519,16 @@ roff_res(struct roff *r, char **bufp, size_t *szp, int pos) res = roff_getstrn(r, stnam, (size_t)i); if (NULL == res) { - cp -= maxl ? 1 : 0; - continue; + mandoc_msg + (MANDOCERR_BADESCAPE, r->parse, + ln, (int)(stesc - *bufp), NULL); + res = ""; } /* Replace the escape sequence by the string. */ + pos = stesc - *bufp; + nsz = *szp + strlen(res) + 1; n = mandoc_malloc(nsz); @@ -441,12 +540,57 @@ roff_res(struct roff *r, char **bufp, size_t *szp, int pos) *bufp = n; *szp = nsz; - return(0); - } - return(1); + if (EXPAND_LIMIT >= ++expand_count) + goto again; + + /* Just leave the string unexpanded. */ + mandoc_msg(MANDOCERR_ROFFLOOP, r->parse, ln, pos, NULL); + return(ROFF_IGN); + } + return(ROFF_CONT); } +/* + * Process text streams: convert all breakable hyphens into ASCII_HYPH. + */ +static enum rofferr +roff_parsetext(char *p) +{ + size_t sz; + const char *start; + enum mandoc_esc esc; + + start = p; + + while ('\0' != *p) { + sz = strcspn(p, "-\\"); + p += sz; + + if ('\0' == *p) + break; + + if ('\\' == *p) { + /* Skip over escapes. */ + p++; + esc = mandoc_escape + ((const char **)/*XXX*/(void *)&p, NULL, NULL); + if (ESCAPE_ERROR == esc) + break; + continue; + } else if (p == start) { + p++; + continue; + } + + if (isalpha((unsigned char)p[-1]) && + isalpha((unsigned char)p[1])) + *p = ASCII_HYPH; + p++; + } + + return(ROFF_CONT); +} enum rofferr roff_parseln(struct roff *r, int ln, char **bufp, @@ -454,40 +598,55 @@ roff_parseln(struct roff *r, int ln, char **bufp, { enum rofft t; enum rofferr e; - int ppos; + int ppos, ctl; /* * Run the reserved-word filter only if we have some reserved * words to fill in. */ - if (r->first_string && ! roff_res(r, bufp, szp, pos)) - return(ROFF_REPARSE); + e = roff_res(r, bufp, szp, ln, pos); + if (ROFF_IGN == e) + return(e); + assert(ROFF_CONT == e); + + ppos = pos; + ctl = mandoc_getcontrol(*bufp, &pos); /* * First, if a scope is open and we're not a macro, pass the * text through the macro's filter. If a scope isn't open and * we're not a macro, just let it through. + * Finally, if there's an equation scope open, divert it into it + * no matter our state. */ - if (r->last && ! ROFF_CTL((*bufp)[pos])) { + if (r->last && ! ctl) { t = r->last->tok; assert(roffs[t].text); e = (*roffs[t].text) (r, t, bufp, szp, ln, pos, pos, offs); assert(ROFF_IGN == e || ROFF_CONT == e); - if (ROFF_CONT == e && r->tbl) - return(tbl_read(r->tbl, ln, *bufp, *offs)); - return(e); - } else if ( ! ROFF_CTL((*bufp)[pos])) { + if (ROFF_CONT != e) + return(e); + if (r->eqn) + return(eqn_read(&r->eqn, ln, *bufp, pos, offs)); if (r->tbl) - return(tbl_read(r->tbl, ln, *bufp, *offs)); - return(ROFF_CONT); - } + return(tbl_read(r->tbl, ln, *bufp, pos)); + return(roff_parsetext(*bufp + pos)); + } else if ( ! ctl) { + if (r->eqn) + return(eqn_read(&r->eqn, ln, *bufp, pos, offs)); + if (r->tbl) + return(tbl_read(r->tbl, ln, *bufp, pos)); + return(roff_parsetext(*bufp + pos)); + } else if (r->eqn) + return(eqn_read(&r->eqn, ln, *bufp, ppos, offs)); /* * If a scope is open, go to the child handler for that macro, * as it may want to preprocess before doing anything with it. + * Don't do so if an equation is open. */ if (r->last) { @@ -495,7 +654,7 @@ roff_parseln(struct roff *r, int ln, char **bufp, assert(roffs[t].sub); return((*roffs[t].sub) (r, t, bufp, szp, - ln, pos, pos, offs)); + ln, ppos, pos, offs)); } /* @@ -504,7 +663,6 @@ roff_parseln(struct roff *r, int ln, char **bufp, * the compilers handle it. */ - ppos = pos; if (ROFF_MAX == (t = roff_parse(r, *bufp, &pos))) return(ROFF_CONT); @@ -520,18 +678,22 @@ roff_endparse(struct roff *r) { if (r->last) - (*r->msg)(MANDOCERR_SCOPEEXIT, r->data, + mandoc_msg(MANDOCERR_SCOPEEXIT, r->parse, r->last->line, r->last->col, NULL); + if (r->eqn) { + mandoc_msg(MANDOCERR_SCOPEEXIT, r->parse, + r->eqn->eqn.ln, r->eqn->eqn.pos, NULL); + eqn_end(&r->eqn); + } + if (r->tbl) { - (*r->msg)(MANDOCERR_SCOPEEXIT, r->data, + mandoc_msg(MANDOCERR_SCOPEEXIT, r->parse, r->tbl->line, r->tbl->pos, NULL); - tbl_end(r->tbl); - r->tbl = NULL; + tbl_end(&r->tbl); } } - /* * Parse a roff node's type from the input buffer. This must be in the * form of ".foo xxx" in the usual way. @@ -543,49 +705,30 @@ roff_parse(struct roff *r, const char *buf, int *pos) size_t maclen; enum rofft t; - assert(ROFF_CTL(buf[*pos])); - (*pos)++; - - while (' ' == buf[*pos] || '\t' == buf[*pos]) - (*pos)++; - - if ('\0' == buf[*pos]) + if ('\0' == buf[*pos] || '"' == buf[*pos] || + '\t' == buf[*pos] || ' ' == buf[*pos]) return(ROFF_MAX); + /* + * We stop the macro parse at an escape, tab, space, or nil. + * However, `\}' is also a valid macro, so make sure we don't + * clobber it by seeing the `\' as the end of token. + */ + mac = buf + *pos; - maclen = strcspn(mac, " \\\t\0"); + maclen = strcspn(mac + 1, " \\\t\0") + 1; t = (r->current_string = roff_getstrn(r, mac, maclen)) - ? ROFF_USERDEF : roff_hash_find(mac, maclen); + ? ROFF_USERDEF : roffhash_find(mac, maclen); + + *pos += (int)maclen; - *pos += maclen; while (buf[*pos] && ' ' == buf[*pos]) (*pos)++; return(t); } - -static int -roff_parse_nat(const char *buf, unsigned int *res) -{ - char *ep; - long lval; - - errno = 0; - lval = strtol(buf, &ep, 10); - if (buf[0] == '\0' || *ep != '\0') - return(0); - if ((errno == ERANGE && - (lval == LONG_MAX || lval == LONG_MIN)) || - (lval > INT_MAX || lval < 0)) - return(0); - - *res = (unsigned int)lval; - return(1); -} - - /* ARGSUSED */ static enum rofferr roff_cblock(ROFF_ARGS) @@ -597,7 +740,7 @@ roff_cblock(ROFF_ARGS) */ if (NULL == r->last) { - (*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL); + mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL); return(ROFF_IGN); } @@ -616,12 +759,12 @@ roff_cblock(ROFF_ARGS) case (ROFF_ig): break; default: - (*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL); + mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL); return(ROFF_IGN); } if ((*bufp)[pos]) - (*r->msg)(MANDOCERR_ARGSLOST, r->data, ln, pos, NULL); + mandoc_msg(MANDOCERR_ARGSLOST, r->parse, ln, pos, NULL); roffnode_pop(r); roffnode_cleanscope(r); @@ -648,7 +791,7 @@ roff_ccond(ROFF_ARGS) { if (NULL == r->last) { - (*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL); + mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL); return(ROFF_IGN); } @@ -660,17 +803,17 @@ roff_ccond(ROFF_ARGS) case (ROFF_if): break; default: - (*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL); + mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL); return(ROFF_IGN); } if (r->last->endspan > -1) { - (*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL); + mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL); return(ROFF_IGN); } if ((*bufp)[pos]) - (*r->msg)(MANDOCERR_ARGSLOST, r->data, ln, pos, NULL); + mandoc_msg(MANDOCERR_ARGSLOST, r->parse, ln, pos, NULL); roffnode_pop(r); roffnode_cleanscope(r); @@ -690,7 +833,7 @@ roff_block(ROFF_ARGS) if (ROFF_ig != tok) { if ('\0' == (*bufp)[pos]) { - (*r->msg)(MANDOCERR_NOARGS, r->data, ln, ppos, NULL); + mandoc_msg(MANDOCERR_NOARGS, r->parse, ln, ppos, NULL); return(ROFF_IGN); } @@ -704,13 +847,13 @@ roff_block(ROFF_ARGS) if (ROFF_de == tok) name = *bufp + pos; else - (*r->msg)(MANDOCERR_REQUEST, r->data, ln, ppos, + mandoc_msg(MANDOCERR_REQUEST, r->parse, ln, ppos, roffs[tok].name); - while ((*bufp)[pos] && ' ' != (*bufp)[pos]) + while ((*bufp)[pos] && ! isspace((unsigned char)(*bufp)[pos])) pos++; - while (' ' == (*bufp)[pos]) + while (isspace((unsigned char)(*bufp)[pos])) (*bufp)[pos++] = '\0'; } @@ -731,9 +874,7 @@ roff_block(ROFF_ARGS) /* If present, process the custom end-of-line marker. */ sv = pos; - while ((*bufp)[pos] && - ' ' != (*bufp)[pos] && - '\t' != (*bufp)[pos]) + while ((*bufp)[pos] && ! isspace((unsigned char)(*bufp)[pos])) pos++; /* @@ -754,7 +895,7 @@ roff_block(ROFF_ARGS) r->last->end[(int)sz] = '\0'; if ((*bufp)[pos]) - (*r->msg)(MANDOCERR_ARGSLOST, r->data, ln, pos, NULL); + mandoc_msg(MANDOCERR_ARGSLOST, r->parse, ln, pos, NULL); return(ROFF_IGN); } @@ -777,11 +918,7 @@ roff_block_sub(ROFF_ARGS) */ if (r->last->end) { - i = pos + 1; - while (' ' == (*bufp)[i] || '\t' == (*bufp)[i]) - i++; - - for (j = 0; r->last->end[j]; j++, i++) + for (i = pos, j = 0; r->last->end[j]; j++, i++) if ((*bufp)[i] != r->last->end[j]) break; @@ -792,6 +929,10 @@ roff_block_sub(ROFF_ARGS) roffnode_pop(r); roffnode_cleanscope(r); + while (' ' == (*bufp)[i] || '\t' == (*bufp)[i]) + i++; + + pos = i; if (ROFF_MAX != roff_parse(r, *bufp, &pos)) return(ROFF_RERUN); return(ROFF_IGN); @@ -803,7 +944,6 @@ roff_block_sub(ROFF_ARGS) * pulling it out of the hashtable. */ - ppos = pos; t = roff_parse(r, *bufp, &pos); /* @@ -840,22 +980,44 @@ roff_cond_sub(ROFF_ARGS) { enum rofft t; enum roffrule rr; + char *ep; - ppos = pos; rr = r->last->rule; - - /* - * Clean out scope. If we've closed ourselves, then don't - * continue. - */ - roffnode_cleanscope(r); + /* + * If the macro is unknown, first check if it contains a closing + * delimiter `\}'. If it does, close out our scope and return + * the currently-scoped rule (ignore or continue). Else, drop + * into the currently-scoped rule. + */ + if (ROFF_MAX == (t = roff_parse(r, *bufp, &pos))) { - if ('\\' == (*bufp)[pos] && '}' == (*bufp)[pos + 1]) - return(roff_ccond - (r, ROFF_ccond, bufp, szp, - ln, pos, pos + 2, offs)); + ep = &(*bufp)[pos]; + for ( ; NULL != (ep = strchr(ep, '\\')); ep++) { + ep++; + if ('}' != *ep) + continue; + + /* + * Make the \} go away. + * This is a little haphazard, as it's not quite + * clear how nroff does this. + * If we're at the end of line, then just chop + * off the \} and resize the buffer. + * If we aren't, then conver it to spaces. + */ + + if ('\0' == *(ep + 1)) { + *--ep = '\0'; + *szp -= 2; + } else + *(ep - 1) = *ep = ' '; + + roff_ccond(r, ROFF_ccond, bufp, szp, + ln, pos, pos + 2, offs); + break; + } return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT); } @@ -864,6 +1026,7 @@ roff_cond_sub(ROFF_ARGS) * if they're either structurally required (such as loops and * conditionals) or a closing macro. */ + if (ROFFRULE_DENY == rr) if ( ! (ROFFMAC_STRUCT & roffs[t].flags)) if (ROFF_ccond != t) @@ -874,37 +1037,28 @@ roff_cond_sub(ROFF_ARGS) ln, ppos, pos, offs)); } - /* ARGSUSED */ static enum rofferr roff_cond_text(ROFF_ARGS) { - char *ep, *st; + char *ep; enum roffrule rr; rr = r->last->rule; - - /* - * We display the value of the text if out current evaluation - * scope permits us to do so. - */ - - /* FIXME: use roff_ccond? */ - - st = &(*bufp)[pos]; - if (NULL == (ep = strstr(st, "\\}"))) { - roffnode_cleanscope(r); - return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT); - } - - if (ep == st || (ep > st && '\\' != *(ep - 1))) - roffnode_pop(r); - roffnode_cleanscope(r); + + ep = &(*bufp)[pos]; + for ( ; NULL != (ep = strchr(ep, '\\')); ep++) { + ep++; + if ('}' != *ep) + continue; + *ep = '&'; + roff_ccond(r, ROFF_ccond, bufp, szp, + ln, pos, pos + 2, offs); + } return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT); } - static enum roffrule roff_evalcond(const char *v, int *pos) { @@ -934,15 +1088,9 @@ static enum rofferr roff_line_ignore(ROFF_ARGS) { - return(ROFF_IGN); -} + if (ROFF_it == tok) + mandoc_msg(MANDOCERR_REQUEST, r->parse, ln, ppos, "it"); -/* ARGSUSED */ -static enum rofferr -roff_line_error(ROFF_ARGS) -{ - - (*r->msg)(MANDOCERR_REQUEST, r->data, ln, ppos, roffs[tok].name); return(ROFF_IGN); } @@ -953,29 +1101,20 @@ roff_cond(ROFF_ARGS) int sv; enum roffrule rule; - /* Stack overflow! */ + /* + * An `.el' has no conditional body: it will consume the value + * of the current rstack entry set in prior `ie' calls or + * defaults to DENY. + * + * If we're not an `el', however, then evaluate the conditional. + */ - if (ROFF_ie == tok && r->rstackpos == RSTACK_MAX - 1) { - (*r->msg)(MANDOCERR_MEM, r->data, ln, ppos, NULL); - return(ROFF_ERR); - } - - /* First, evaluate the conditional. */ - - if (ROFF_el == tok) { - /* - * An `.el' will get the value of the current rstack - * entry set in prior `ie' calls or defaults to DENY. - */ - if (r->rstackpos < 0) - rule = ROFFRULE_DENY; - else - rule = r->rstack[r->rstackpos]; - } else - rule = roff_evalcond(*bufp, &pos); + rule = ROFF_el == tok ? + (r->rstackpos < 0 ? + ROFFRULE_DENY : r->rstack[r->rstackpos--]) : + roff_evalcond(*bufp, &pos); sv = pos; - while (' ' == (*bufp)[pos]) pos++; @@ -987,7 +1126,7 @@ roff_cond(ROFF_ARGS) */ if ('\0' == (*bufp)[pos] && sv != pos) { - (*r->msg)(MANDOCERR_NOARGS, r->data, ln, ppos, NULL); + mandoc_msg(MANDOCERR_NOARGS, r->parse, ln, ppos, NULL); return(ROFF_IGN); } @@ -995,16 +1134,20 @@ roff_cond(ROFF_ARGS) r->last->rule = rule; + /* + * An if-else will put the NEGATION of the current evaluated + * conditional into the stack of rules. + */ + if (ROFF_ie == tok) { - /* - * An if-else will put the NEGATION of the current - * evaluated conditional into the stack. - */ - r->rstackpos++; - if (ROFFRULE_DENY == r->last->rule) - r->rstack[r->rstackpos] = ROFFRULE_ALLOW; - else - r->rstack[r->rstackpos] = ROFFRULE_DENY; + if (r->rstackpos == RSTACK_MAX - 1) { + mandoc_msg(MANDOCERR_MEM, + r->parse, ln, ppos, NULL); + return(ROFF_ERR); + } + r->rstack[++r->rstackpos] = + ROFFRULE_DENY == r->last->rule ? + ROFFRULE_ALLOW : ROFFRULE_DENY; } /* If the parent has false as its rule, then so do we. */ @@ -1056,25 +1199,13 @@ roff_ds(ROFF_ARGS) * will have `bar " ' as its value. */ - name = *bufp + pos; + string = *bufp + pos; + name = roff_getname(r, &string, ln, pos); if ('\0' == *name) return(ROFF_IGN); - string = name; - /* Read until end of name. */ - while (*string && ' ' != *string) - string++; - - /* Nil-terminate name. */ - if (*string) - *(string++) = '\0'; - - /* Read past spaces. */ - while (*string && ' ' == *string) - string++; - - /* Read passed initial double-quote. */ - if (*string && '"' == *string) + /* Read past initial double-quote. */ + if ('"' == *string) string++; /* The rest is the value. */ @@ -1082,56 +1213,75 @@ roff_ds(ROFF_ARGS) return(ROFF_IGN); } +int +roff_regisset(const struct roff *r, enum regs reg) +{ + + return(r->regs[(int)reg].set); +} + +unsigned int +roff_regget(const struct roff *r, enum regs reg) +{ + + return(r->regs[(int)reg].u); +} + +void +roff_regunset(struct roff *r, enum regs reg) +{ + + r->regs[(int)reg].set = 0; +} /* ARGSUSED */ static enum rofferr roff_nr(ROFF_ARGS) { - const char *key, *val; - struct reg *rg; + const char *key; + char *val; + int iv; - key = &(*bufp)[pos]; - rg = r->regs->regs; - - /* Parse register request. */ - while ((*bufp)[pos] && ' ' != (*bufp)[pos]) - pos++; - - /* - * Set our nil terminator. Because this line is going to be - * ignored anyway, we can munge it as we please. - */ - if ((*bufp)[pos]) - (*bufp)[pos++] = '\0'; - - /* Skip whitespace to register token. */ - while ((*bufp)[pos] && ' ' == (*bufp)[pos]) - pos++; - - val = &(*bufp)[pos]; - - /* Process register token. */ + val = *bufp + pos; + key = roff_getname(r, &val, ln, pos); if (0 == strcmp(key, "nS")) { - rg[(int)REG_nS].set = 1; - if ( ! roff_parse_nat(val, &rg[(int)REG_nS].v.u)) - rg[(int)REG_nS].v.u = 0; + r->regs[(int)REG_nS].set = 1; + if ((iv = mandoc_strntoi(val, strlen(val), 10)) >= 0) + r->regs[(int)REG_nS].u = (unsigned)iv; + else + r->regs[(int)REG_nS].u = 0u; } return(ROFF_IGN); } +/* ARGSUSED */ +static enum rofferr +roff_rm(ROFF_ARGS) +{ + const char *name; + char *cp; + + cp = *bufp + pos; + while ('\0' != *cp) { + name = roff_getname(r, &cp, ln, (int)(cp - *bufp)); + if ('\0' != *name) + roff_setstr(r, name, NULL, 0); + } + return(ROFF_IGN); +} + /* ARGSUSED */ static enum rofferr roff_TE(ROFF_ARGS) { if (NULL == r->tbl) - (*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL); + mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL); else - tbl_end(r->tbl); + tbl_end(&r->tbl); - r->tbl = NULL; return(ROFF_IGN); } @@ -1141,13 +1291,63 @@ roff_T_(ROFF_ARGS) { if (NULL == r->tbl) - (*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL); + mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL); else tbl_restart(ppos, ln, r->tbl); return(ROFF_IGN); } +#if 0 +static int +roff_closeeqn(struct roff *r) +{ + + return(r->eqn && ROFF_EQN == eqn_end(&r->eqn) ? 1 : 0); +} +#endif + +static void +roff_openeqn(struct roff *r, const char *name, int line, + int offs, const char *buf) +{ + struct eqn_node *e; + int poff; + + assert(NULL == r->eqn); + e = eqn_alloc(name, offs, line, r->parse); + + if (r->last_eqn) + r->last_eqn->next = e; + else + r->first_eqn = r->last_eqn = e; + + r->eqn = r->last_eqn = e; + + if (buf) { + poff = 0; + eqn_read(&r->eqn, line, buf, offs, &poff); + } +} + +/* ARGSUSED */ +static enum rofferr +roff_EQ(ROFF_ARGS) +{ + + roff_openeqn(r, *bufp + pos, ln, ppos, NULL); + return(ROFF_IGN); +} + +/* ARGSUSED */ +static enum rofferr +roff_EN(ROFF_ARGS) +{ + + mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL); + return(ROFF_IGN); +} + /* ARGSUSED */ static enum rofferr roff_TS(ROFF_ARGS) @@ -1155,11 +1355,11 @@ roff_TS(ROFF_ARGS) struct tbl_node *t; if (r->tbl) { - (*r->msg)(MANDOCERR_SCOPEBROKEN, r->data, ln, ppos, NULL); - tbl_end(r->tbl); + mandoc_msg(MANDOCERR_SCOPEBROKEN, r->parse, ln, ppos, NULL); + tbl_end(&r->tbl); } - t = tbl_alloc(ppos, ln, r->data, r->msg); + t = tbl_alloc(ppos, ln, r->parse); if (r->last_tbl) r->last_tbl->next = t; @@ -1170,13 +1370,78 @@ roff_TS(ROFF_ARGS) return(ROFF_IGN); } +/* ARGSUSED */ +static enum rofferr +roff_tr(ROFF_ARGS) +{ + const char *p, *first, *second; + size_t fsz, ssz; + enum mandoc_esc esc; + + p = *bufp + pos; + + if ('\0' == *p) { + mandoc_msg(MANDOCERR_ARGCOUNT, r->parse, ln, ppos, NULL); + return(ROFF_IGN); + } + + while ('\0' != *p) { + fsz = ssz = 1; + + first = p++; + if ('\\' == *first) { + esc = mandoc_escape(&p, NULL, NULL); + if (ESCAPE_ERROR == esc) { + mandoc_msg + (MANDOCERR_BADESCAPE, r->parse, + ln, (int)(p - *bufp), NULL); + return(ROFF_IGN); + } + fsz = (size_t)(p - first); + } + + second = p++; + if ('\\' == *second) { + esc = mandoc_escape(&p, NULL, NULL); + if (ESCAPE_ERROR == esc) { + mandoc_msg + (MANDOCERR_BADESCAPE, r->parse, + ln, (int)(p - *bufp), NULL); + return(ROFF_IGN); + } + ssz = (size_t)(p - second); + } else if ('\0' == *second) { + mandoc_msg(MANDOCERR_ARGCOUNT, r->parse, + ln, (int)(p - *bufp), NULL); + second = " "; + p--; + } + + if (fsz > 1) { + roff_setstrn(&r->xmbtab, first, + fsz, second, ssz, 0); + continue; + } + + if (NULL == r->xtab) + r->xtab = mandoc_calloc + (128, sizeof(struct roffstr)); + + free(r->xtab[(int)*first].p); + r->xtab[(int)*first].p = mandoc_strndup(second, ssz); + r->xtab[(int)*first].sz = ssz; + } + + return(ROFF_IGN); +} + /* ARGSUSED */ static enum rofferr roff_so(ROFF_ARGS) { char *name; - (*r->msg)(MANDOCERR_SO, r->data, ln, ppos, NULL); + mandoc_msg(MANDOCERR_SO, r->parse, ln, ppos, NULL); /* * Handle `so'. Be EXTREMELY careful, as we shouldn't be @@ -1187,7 +1452,7 @@ roff_so(ROFF_ARGS) name = *bufp + pos; if ('/' == *name || strstr(name, "../") || strstr(name, "/..")) { - (*r->msg)(MANDOCERR_SOPATH, r->data, ln, pos, NULL); + mandoc_msg(MANDOCERR_SOPATH, r->parse, ln, pos, NULL); return(ROFF_ERR); } @@ -1210,7 +1475,7 @@ roff_userdef(ROFF_ARGS) cp = *bufp + pos; for (i = 0; i < 9; i++) arg[i] = '\0' == *cp ? "" : - mandoc_getarg(&cp, r->msg, r->data, ln, &pos); + mandoc_getarg(r->parse, &cp, ln, &pos); /* * Expand macro arguments. @@ -1250,6 +1515,39 @@ roff_userdef(ROFF_ARGS) ROFF_REPARSE : ROFF_APPEND); } +static char * +roff_getname(struct roff *r, char **cpp, int ln, int pos) +{ + char *name, *cp; + + name = *cpp; + if ('\0' == *name) + return(name); + + /* Read until end of name. */ + for (cp = name; '\0' != *cp && ' ' != *cp; cp++) { + if ('\\' != *cp) + continue; + cp++; + if ('\\' == *cp) + continue; + mandoc_msg(MANDOCERR_NAMESC, r->parse, ln, pos, NULL); + *cp = '\0'; + name = cp; + } + + /* Nil-terminate name. */ + if ('\0' != *cp) + *(cp++) = '\0'; + + /* Read past spaces. */ + while (' ' == *cp) + cp++; + + *cpp = cp; + return(name); +} + /* * Store *string into the user-defined string called *name. * In multiline mode, append to an existing entry and append '\n'; @@ -1260,26 +1558,40 @@ static void roff_setstr(struct roff *r, const char *name, const char *string, int multiline) { - struct roffstr *n; - char *c; - size_t oldch, newch; + + roff_setstrn(&r->strtab, name, strlen(name), string, + string ? strlen(string) : 0, multiline); +} + +static void +roff_setstrn(struct roffkv **r, const char *name, size_t namesz, + const char *string, size_t stringsz, int multiline) +{ + struct roffkv *n; + char *c; + int i; + size_t oldch, newch; /* Search for an existing string with the same name. */ - n = r->first_string; - while (n && strcmp(name, n->name)) + n = *r; + + while (n && strcmp(name, n->key.p)) n = n->next; if (NULL == n) { /* Create a new string table entry. */ - n = mandoc_malloc(sizeof(struct roffstr)); - n->name = mandoc_strdup(name); - n->string = NULL; - n->next = r->first_string; - r->first_string = n; + n = mandoc_malloc(sizeof(struct roffkv)); + n->key.p = mandoc_strndup(name, namesz); + n->key.sz = namesz; + n->val.p = NULL; + n->val.sz = 0; + n->next = *r; + *r = n; } else if (0 == multiline) { /* In multiline mode, append; else replace. */ - free(n->string); - n->string = NULL; + free(n->val.p); + n->val.p = NULL; + n->val.sz = 0; } if (NULL == string) @@ -1289,63 +1601,64 @@ roff_setstr(struct roff *r, const char *name, const char *string, * One additional byte for the '\n' in multiline mode, * and one for the terminating '\0'. */ - newch = strlen(string) + (multiline ? 2 : 1); - if (NULL == n->string) { - n->string = mandoc_malloc(newch); - *n->string = '\0'; + newch = stringsz + (multiline ? 2u : 1u); + + if (NULL == n->val.p) { + n->val.p = mandoc_malloc(newch); + *n->val.p = '\0'; oldch = 0; } else { - oldch = strlen(n->string); - n->string = mandoc_realloc(n->string, oldch + newch); + oldch = n->val.sz; + n->val.p = mandoc_realloc(n->val.p, oldch + newch); } /* Skip existing content in the destination buffer. */ - c = n->string + oldch; + c = n->val.p + (int)oldch; /* Append new content to the destination buffer. */ - while (*string) { + i = 0; + while (i < (int)stringsz) { /* * Rudimentary roff copy mode: * Handle escaped backslashes. */ - if ('\\' == *string && '\\' == *(string + 1)) - string++; - *c++ = *string++; + if ('\\' == string[i] && '\\' == string[i + 1]) + i++; + *c++ = string[i++]; } /* Append terminating bytes. */ if (multiline) *c++ = '\n'; - *c = '\0'; -} + *c = '\0'; + n->val.sz = (int)(c - n->val.p); +} static const char * roff_getstrn(const struct roff *r, const char *name, size_t len) { - const struct roffstr *n; + const struct roffkv *n; - n = r->first_string; - while (n && (strncmp(name, n->name, len) || '\0' != n->name[(int)len])) - n = n->next; + for (n = r->strtab; n; n = n->next) + if (0 == strncmp(name, n->key.p, len) && + '\0' == n->key.p[(int)len]) + return(n->val.p); - return(n ? n->string : NULL); + return(NULL); } - static void -roff_freestr(struct roff *r) +roff_freestr(struct roffkv *r) { - struct roffstr *n, *nn; + struct roffkv *n, *nn; - for (n = r->first_string; n; n = nn) { - free(n->name); - free(n->string); + for (n = r; n; n = nn) { + free(n->key.p); + free(n->val.p); nn = n->next; free(n); } - - r->first_string = NULL; } const struct tbl_span * @@ -1354,3 +1667,102 @@ roff_span(const struct roff *r) return(r->tbl ? tbl_span(r->tbl) : NULL); } + +const struct eqn * +roff_eqn(const struct roff *r) +{ + + return(r->last_eqn ? &r->last_eqn->eqn : NULL); +} + +/* + * Duplicate an input string, making the appropriate character + * conversations (as stipulated by `tr') along the way. + * Returns a heap-allocated string with all the replacements made. + */ +char * +roff_strdup(const struct roff *r, const char *p) +{ + const struct roffkv *cp; + char *res; + const char *pp; + size_t ssz, sz; + enum mandoc_esc esc; + + if (NULL == r->xmbtab && NULL == r->xtab) + return(mandoc_strdup(p)); + else if ('\0' == *p) + return(mandoc_strdup("")); + + /* + * Step through each character looking for term matches + * (remember that a `tr' can be invoked with an escape, which is + * a glyph but the escape is multi-character). + * We only do this if the character hash has been initialised + * and the string is >0 length. + */ + + res = NULL; + ssz = 0; + + while ('\0' != *p) { + if ('\\' != *p && r->xtab && r->xtab[(int)*p].p) { + sz = r->xtab[(int)*p].sz; + res = mandoc_realloc(res, ssz + sz + 1); + memcpy(res + ssz, r->xtab[(int)*p].p, sz); + ssz += sz; + p++; + continue; + } else if ('\\' != *p) { + res = mandoc_realloc(res, ssz + 2); + res[ssz++] = *p++; + continue; + } + + /* Search for term matches. */ + for (cp = r->xmbtab; cp; cp = cp->next) + if (0 == strncmp(p, cp->key.p, cp->key.sz)) + break; + + if (NULL != cp) { + /* + * A match has been found. + * Append the match to the array and move + * forward by its keysize. + */ + res = mandoc_realloc + (res, ssz + cp->val.sz + 1); + memcpy(res + ssz, cp->val.p, cp->val.sz); + ssz += cp->val.sz; + p += (int)cp->key.sz; + continue; + } + + /* + * Handle escapes carefully: we need to copy + * over just the escape itself, or else we might + * do replacements within the escape itself. + * Make sure to pass along the bogus string. + */ + pp = p++; + esc = mandoc_escape(&p, NULL, NULL); + if (ESCAPE_ERROR == esc) { + sz = strlen(pp); + res = mandoc_realloc(res, ssz + sz + 1); + memcpy(res + ssz, pp, sz); + break; + } + /* + * We bail out on bad escapes. + * No need to warn: we already did so when + * roff_res() was called. + */ + sz = (int)(p - pp); + res = mandoc_realloc(res, ssz + sz + 1); + memcpy(res + ssz, pp, sz); + ssz += sz; + } + + res[(int)ssz] = '\0'; + return(res); +} diff --git a/external/bsd/mdocml/dist/roff.h b/external/bsd/mdocml/dist/roff.h deleted file mode 100644 index d7c35831a..000000000 --- a/external/bsd/mdocml/dist/roff.h +++ /dev/null @@ -1,45 +0,0 @@ -/* $Vendor-Id: roff.h,v 1.22 2011/01/01 16:18:39 kristaps Exp $ */ -/* - * Copyright (c) 2010 Kristaps Dzonsons <kristaps@bsd.lv> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -#ifndef ROFF_H -#define ROFF_H - -enum rofferr { - ROFF_CONT, /* continue processing line */ - ROFF_RERUN, /* re-run roff interpreter with offset */ - ROFF_APPEND, /* re-run main parser, appending next line */ - ROFF_REPARSE, /* re-run main parser on the result */ - ROFF_SO, /* include another file */ - ROFF_IGN, /* ignore current line */ - ROFF_TBL, /* a table row was successfully parsed */ - ROFF_ERR /* badness: puke and stop */ -}; - -__BEGIN_DECLS - -struct roff; - -void roff_free(struct roff *); -struct roff *roff_alloc(struct regset *, void *, mandocmsg); -void roff_reset(struct roff *); -enum rofferr roff_parseln(struct roff *, int, - char **, size_t *, int, int *); -void roff_endparse(struct roff *); -const struct tbl_span *roff_span(const struct roff *); - -__END_DECLS - -#endif /*!ROFF_H*/ diff --git a/external/bsd/mdocml/dist/st.c b/external/bsd/mdocml/dist/st.c index 05f28a38a..fb506daab 100644 --- a/external/bsd/mdocml/dist/st.c +++ b/external/bsd/mdocml/dist/st.c @@ -1,4 +1,4 @@ -/* $Vendor-Id: st.c,v 1.8 2010/06/19 20:46:28 kristaps Exp $ */ +/* $Vendor-Id: st.c,v 1.9 2011/03/22 14:33:05 kristaps Exp $ */ /* * Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -22,6 +22,7 @@ #include <string.h> #include <time.h> +#include "mdoc.h" #include "mandoc.h" #include "libmdoc.h" diff --git a/external/bsd/mdocml/dist/st.in b/external/bsd/mdocml/dist/st.in index 5ca9a64ed..610ce0ced 100644 --- a/external/bsd/mdocml/dist/st.in +++ b/external/bsd/mdocml/dist/st.in @@ -1,4 +1,4 @@ -/* $Vendor-Id: st.in,v 1.15 2010/07/31 23:52:58 schwarze Exp $ */ +/* $Vendor-Id: st.in,v 1.18 2012/01/03 10:18:05 kristaps Exp $ */ /* * Copyright (c) 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -22,6 +22,8 @@ * the formatted output string. * * Be sure to escape strings. + * The non-breaking blanks prevent ending an output line right before + * a number. Groff prevent line breaks at the same places. * * REMEMBER TO ADD NEW STANDARDS TO MDOC.7! */ @@ -43,32 +45,34 @@ LINE("-p1003.2a-92", "IEEE Std 1003.2a-1992 (\\(lqPOSIX.2\\(rq)") LINE("-p1387.2-95", "IEEE Std 1387.2-1995 (\\(lqPOSIX.7.2\\(rq)") LINE("-p1003.2", "IEEE Std 1003.2 (\\(lqPOSIX.2\\(rq)") LINE("-p1387.2", "IEEE Std 1387.2 (\\(lqPOSIX.7.2\\(rq)") -LINE("-isoC", "ISO/IEC 9899:1990 (\\(lqISO C90\\(rq)") -LINE("-isoC-90", "ISO/IEC 9899:1990 (\\(lqISO C90\\(rq)") -LINE("-isoC-amd1", "ISO/IEC 9899/AMD1:1995 (\\(lqISO C90\\(rq)") -LINE("-isoC-tcor1", "ISO/IEC 9899/TCOR1:1994 (\\(lqISO C90\\(rq)") -LINE("-isoC-tcor2", "ISO/IEC 9899/TCOR2:1995 (\\(lqISO C90\\(rq)") -LINE("-isoC-99", "ISO/IEC 9899:1999 (\\(lqISO C99\\(rq)") +LINE("-isoC", "ISO/IEC 9899:1990 (\\(lqISO\\~C90\\(rq)") +LINE("-isoC-90", "ISO/IEC 9899:1990 (\\(lqISO\\~C90\\(rq)") +LINE("-isoC-amd1", "ISO/IEC 9899/AMD1:1995 (\\(lqISO\\~C90, Amendment 1\\(rq)") +LINE("-isoC-tcor1", "ISO/IEC 9899/TCOR1:1994 (\\(lqISO\\~C90, Technical Corrigendum 1\\(rq)") +LINE("-isoC-tcor2", "ISO/IEC 9899/TCOR2:1995 (\\(lqISO\\~C90, Technical Corrigendum 2\\(rq)") +LINE("-isoC-99", "ISO/IEC 9899:1999 (\\(lqISO\\~C99\\(rq)") +LINE("-isoC-2011", "ISO/IEC 9899:2011 (\\(lqISO\\~C11\\(rq)") LINE("-iso9945-1-90", "ISO/IEC 9945-1:1990 (\\(lqPOSIX.1\\(rq)") LINE("-iso9945-1-96", "ISO/IEC 9945-1:1996 (\\(lqPOSIX.1\\(rq)") LINE("-iso9945-2-93", "ISO/IEC 9945-2:1993 (\\(lqPOSIX.2\\(rq)") -LINE("-ansiC", "ANSI X3.159-1989 (\\(lqANSI C\\(rq)") -LINE("-ansiC-89", "ANSI X3.159-1989 (\\(lqANSI C\\(rq)") -LINE("-ansiC-99", "ANSI/ISO/IEC 9899-1999 (\\(lqANSI C99\\(rq)") +LINE("-ansiC", "ANSI X3.159-1989 (\\(lqANSI\\~C89\\(rq)") +LINE("-ansiC-89", "ANSI X3.159-1989 (\\(lqANSI\\~C89\\(rq)") +LINE("-ansiC-99", "ANSI/ISO/IEC 9899-1999 (\\(lqANSI\\~C99\\(rq)") LINE("-ieee754", "IEEE Std 754-1985") LINE("-iso8802-3", "ISO 8802-3: 1989") +LINE("-iso8601", "ISO 8601") LINE("-ieee1275-94", "IEEE Std 1275-1994 (\\(lqOpen Firmware\\(rq)") -LINE("-xpg3", "X/Open Portability Guide Issue 3 (\\(lqXPG3\\(rq)") -LINE("-xpg4", "X/Open Portability Guide Issue 4 (\\(lqXPG4\\(rq)") -LINE("-xpg4.2", "X/Open Portability Guide Issue 4.2 (\\(lqXPG4.2\\(rq)") -LINE("-xpg4.3", "X/Open Portability Guide Issue 4.3 (\\(lqXPG4.3\\(rq)") -LINE("-xbd5", "X/Open System Interface Definitions Issue 5 (\\(lqXBD5\\(rq)") -LINE("-xcu5", "X/Open Commands and Utilities Issue 5 (\\(lqXCU5\\(rq)") -LINE("-xsh5", "X/Open System Interfaces and Headers Issue 5 (\\(lqXSH5\\(rq)") -LINE("-xns5", "X/Open Networking Services Issue 5 (\\(lqXNS5\\(rq)") -LINE("-xns5.2", "X/Open Networking Services Issue 5.2 (\\(lqXNS5.2\\(rq)") -LINE("-xns5.2d2.0", "X/Open Networking Services Issue 5.2 Draft 2.0 (\\(lqXNS5.2D2.0\\(rq)") -LINE("-xcurses4.2", "X/Open Curses Issue 4 Version 2 (\\(lqXCURSES4.2\\(rq)") -LINE("-susv2", "Version 2 of the Single UNIX Specification") -LINE("-susv3", "Version 3 of the Single UNIX Specification") -LINE("-svid4", "System V Interface Definition, Fourth Edition (\\(lqSVID4\\(rq)") +LINE("-xpg3", "X/Open Portability Guide Issue\\~3 (\\(lqXPG3\\(rq)") +LINE("-xpg4", "X/Open Portability Guide Issue\\~4 (\\(lqXPG4\\(rq)") +LINE("-xpg4.2", "X/Open Portability Guide Issue\\~4, Version\\~2 (\\(lqXPG4.2\\(rq)") +LINE("-xpg4.3", "X/Open Portability Guide Issue\\~4, Version\\~3 (\\(lqXPG4.3\\(rq)") +LINE("-xbd5", "X/Open System Interface Definitions Issue\\~5 (\\(lqXBD5\\(rq)") +LINE("-xcu5", "X/Open Commands and Utilities Issue\\~5 (\\(lqXCU5\\(rq)") +LINE("-xsh5", "X/Open System Interfaces and Headers Issue\\~5 (\\(lqXSH5\\(rq)") +LINE("-xns5", "X/Open Networking Services Issue\\~5 (\\(lqXNS5\\(rq)") +LINE("-xns5.2", "X/Open Networking Services Issue\\~5.2 (\\(lqXNS5.2\\(rq)") +LINE("-xns5.2d2.0", "X/Open Networking Services Issue\\~5.2 Draft\\~2.0 (\\(lqXNS5.2D2.0\\(rq)") +LINE("-xcurses4.2", "X/Open Curses Issue\\~4, Version\\~2 (\\(lqXCURSES4.2\\(rq)") +LINE("-susv2", "Version\\~2 of the Single UNIX Specification") +LINE("-susv3", "Version\\~3 of the Single UNIX Specification") +LINE("-svid4", "System\\~V Interface Definition, Fourth Edition (\\(lqSVID4\\(rq)") diff --git a/external/bsd/mdocml/dist/tbl.7 b/external/bsd/mdocml/dist/tbl.7 index 0bd343ee0..b55987f57 100644 --- a/external/bsd/mdocml/dist/tbl.7 +++ b/external/bsd/mdocml/dist/tbl.7 @@ -1,6 +1,6 @@ -.\" $Vendor-Id: tbl.7,v 1.4 2011/01/07 14:59:52 kristaps Exp $ +.\" $Vendor-Id: tbl.7,v 1.16 2011/09/03 00:29:21 kristaps Exp $ .\" -.\" Copyright (c) 2010 Kristaps Dzonsons <kristaps@bsd.lv> +.\" Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above @@ -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 January 7, 2011 +.Dd September 3, 2011 .Dt TBL 7 .Os .Sh NAME @@ -49,7 +49,7 @@ macro tags, whose precise syntax is documented in Tables consist of a series of options on a single line, followed by the table layout, followed by data. .Pp -For example, the following creates a boxed table with digits centered in +For example, the following creates a boxed table with digits centred in the cells. .Bd -literal -offset indent \&.TS @@ -69,6 +69,13 @@ c5 c5 c5. 4:5:6 .TE .Ed +.Pp +The +.Nm +implementation in +.Xr mandoc 1 +is +.Ud .Sh TABLE STRUCTURE Tables are enclosed by the .Sq TS @@ -180,8 +187,6 @@ Accepts a single-character argument. This character will be used as the decimal point with the .Cm n layout key. -This option is not supported by -.Xr mandoc 1 . .It Cm nospaces This option is not supported by .Xr mandoc 1 . @@ -205,18 +210,29 @@ Right-justify a literal string within its column. .It Cm l Left-justify a literal string within its column. .It Cm n -Justify a number around its decimal point. +Justify a number around its last decimal point. If the decimal point is not found on the number, it's assumed to trail the number. .It Cm s +Horizontally span columns from the last +.No non- Ns Cm s +data cell. +It is an error if spanning columns follow a +.Cm \- +or +.Cm \(ba +cell, or come first. This option is not supported by .Xr mandoc 1 . .It Cm a -This option is not supported by -.Xr mandoc 1 . +Left-justify a literal string and pad with one space. .It Cm ^ -This option is not supported by -.Xr mandoc 1 . +Vertically span rows from the last +.No non- Ns Cm ^ +data cell. +It is an error to invoke a vertical span on the first layout row. +Unlike a horizontal spanner, you must specify an empty cell (if it not +empty, the data is discarded) in the corresponding data cell. .It Cm \- Replace the data cell (its contents will be lost) with a single horizontal line. @@ -231,30 +247,39 @@ Emit a vertical bar instead of data. Emit a double-vertical bar instead of data. .El .Pp -For example, the following layout specifies a centre-justified column of -minimum width 10, followed by vertical bar, followed by a left-justified -column of minimum width 10, another vertical bar, then a column -justified about the decimal point in numbers: -.Pp -.Dl c10 | l10 | n -.Pp Keys may be followed by a set of modifiers. A modifier is either a modifier key or a natural number for specifying -spacing. +the minimum width of a column. The following case-insensitive modifier keys are available: .Cm z , .Cm u , .Cm e , .Cm t , .Cm d , -.Cm f , .Cm b , .Cm i , -.Cm b , +.Cm r , and -.Cm i . +.Cm f +.Po +followed by +.Cm b , +.Cm i , +.Cm r , +.Cm 3 , +.Cm 2 , +or +.Cm 1 +.Pc . All of these are ignored by .Xr mandoc 1 . +.Pp +For example, the following layout specifies a centre-justified column of +minimum width 10, followed by vertical bar, followed by a left-justified +column of minimum width 10, another vertical bar, then a column +justified about the decimal point in numbers: +.Pp +.Dl c10 | l10 | n .Ss Data The data section follows the last layout row. By default, cells in a data section are delimited by a tab. @@ -316,7 +341,8 @@ This formed the basis of the implementation that is part of the .Xr mandoc 1 utility. .Sh AUTHORS -This partial +This .Nm reference was written by -.An Kristaps Dzonsons Aq kristaps@bsd.lv . +.An Kristaps Dzonsons , +.Mt kristaps@bsd.lv . diff --git a/external/bsd/mdocml/dist/tbl.c b/external/bsd/mdocml/dist/tbl.c index 34bcfb153..72137b7c2 100644 --- a/external/bsd/mdocml/dist/tbl.c +++ b/external/bsd/mdocml/dist/tbl.c @@ -1,6 +1,7 @@ -/* $Vendor-Id: tbl.c,v 1.21 2011/01/04 15:02:00 kristaps Exp $ */ +/* $Vendor-Id: tbl.c,v 1.26 2011/07/25 15:37:00 kristaps Exp $ */ /* - * Copyright (c) 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -14,6 +15,10 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include <assert.h> #include <stdio.h> #include <stdlib.h> @@ -21,7 +26,6 @@ #include <time.h> #include "mandoc.h" -#include "roff.h" #include "libmandoc.h" #include "libroff.h" @@ -66,15 +70,14 @@ tbl_read(struct tbl_node *tbl, int ln, const char *p, int offs) } struct tbl_node * -tbl_alloc(int pos, int line, void *data, const mandocmsg msg) +tbl_alloc(int pos, int line, struct mparse *parse) { struct tbl_node *p; p = mandoc_calloc(1, sizeof(struct tbl_node)); p->line = line; p->pos = pos; - p->data = data; - p->msg = msg; + p->parse = parse; p->part = TBL_PART_OPTS; p->opts.tab = '\t'; p->opts.linesize = 12; @@ -125,35 +128,48 @@ void tbl_restart(int line, int pos, struct tbl_node *tbl) { if (TBL_PART_CDATA == tbl->part) - TBL_MSG(tbl, MANDOCERR_TBLBLOCK, tbl->line, tbl->pos); + mandoc_msg(MANDOCERR_TBLBLOCK, tbl->parse, + tbl->line, tbl->pos, NULL); tbl->part = TBL_PART_LAYOUT; tbl->line = line; tbl->pos = pos; if (NULL == tbl->first_span || NULL == tbl->first_span->first) - TBL_MSG(tbl, MANDOCERR_TBLNODATA, tbl->line, tbl->pos); + mandoc_msg(MANDOCERR_TBLNODATA, tbl->parse, + tbl->line, tbl->pos, NULL); } const struct tbl_span * -tbl_span(const struct tbl_node *tbl) +tbl_span(struct tbl_node *tbl) { + struct tbl_span *span; assert(tbl); - return(tbl->last_span); + span = tbl->current_span ? tbl->current_span->next + : tbl->first_span; + if (span) + tbl->current_span = span; + return(span); } void -tbl_end(struct tbl_node *tbl) +tbl_end(struct tbl_node **tblp) { + struct tbl_node *tbl; + + tbl = *tblp; + *tblp = NULL; if (NULL == tbl->first_span || NULL == tbl->first_span->first) - TBL_MSG(tbl, MANDOCERR_TBLNODATA, tbl->line, tbl->pos); + mandoc_msg(MANDOCERR_TBLNODATA, tbl->parse, + tbl->line, tbl->pos, NULL); if (tbl->last_span) tbl->last_span->flags |= TBL_SPAN_LAST; if (TBL_PART_CDATA == tbl->part) - TBL_MSG(tbl, MANDOCERR_TBLBLOCK, tbl->line, tbl->pos); + mandoc_msg(MANDOCERR_TBLBLOCK, tbl->parse, + tbl->line, tbl->pos, NULL); } diff --git a/external/bsd/mdocml/dist/tbl_data.c b/external/bsd/mdocml/dist/tbl_data.c index 53d198985..1742c14f3 100644 --- a/external/bsd/mdocml/dist/tbl_data.c +++ b/external/bsd/mdocml/dist/tbl_data.c @@ -1,6 +1,7 @@ -/* $Vendor-Id: tbl_data.c,v 1.15 2011/01/09 23:14:41 kristaps Exp $ */ +/* $Vendor-Id: tbl_data.c,v 1.24 2011/03/20 16:02:05 kristaps Exp $ */ /* - * Copyright (c) 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -28,8 +29,10 @@ #include "libmandoc.h" #include "libroff.h" -static int data(struct tbl_node *, struct tbl_span *, - int, const char *, int *); +static int data(struct tbl_node *, struct tbl_span *, + int, const char *, int *); +static struct tbl_span *newspan(struct tbl_node *, int, + struct tbl_row *); static int data(struct tbl_node *tbl, struct tbl_span *dp, @@ -37,7 +40,7 @@ data(struct tbl_node *tbl, struct tbl_span *dp, { struct tbl_dat *dat; struct tbl_cell *cp; - int sv; + int sv, spans; cp = NULL; if (dp->last && dp->last->layout) @@ -55,12 +58,33 @@ data(struct tbl_node *tbl, struct tbl_span *dp, TBL_CELL_SPAN == cp->pos)) cp = cp->next; + /* + * Stop processing when we reach the end of the available layout + * cells. This means that we have extra input. + */ + + if (NULL == cp) { + mandoc_msg(MANDOCERR_TBLEXTRADAT, + tbl->parse, ln, *pos, NULL); + /* Skip to the end... */ + while (p[*pos]) + (*pos)++; + return(1); + } + dat = mandoc_calloc(1, sizeof(struct tbl_dat)); dat->layout = cp; dat->pos = TBL_DATA_NONE; - if (NULL == dat->layout) - TBL_MSG(tbl, MANDOCERR_TBLEXTRADAT, ln, *pos); + assert(TBL_CELL_SPAN != cp->pos); + + for (spans = 0, cp = cp->next; cp; cp = cp->next) + if (TBL_CELL_SPAN == cp->pos) + spans++; + else + break; + + dat->spans = spans; if (dp->last) { dp->last->next = dat; @@ -83,8 +107,10 @@ data(struct tbl_node *tbl, struct tbl_span *dp, return(0); } - dat->string = mandoc_malloc(*pos - sv + 1); - memcpy(dat->string, &p[sv], *pos - sv); + assert(*pos - sv >= 0); + + dat->string = mandoc_malloc((size_t)(*pos - sv + 1)); + memcpy(dat->string, &p[sv], (size_t)(*pos - sv)); dat->string[*pos - sv] = '\0'; if (p[*pos]) @@ -101,13 +127,12 @@ data(struct tbl_node *tbl, struct tbl_span *dp, else dat->pos = TBL_DATA_DATA; - if (NULL == dat->layout) - return(1); - if (TBL_CELL_HORIZ == dat->layout->pos || - TBL_CELL_DHORIZ == dat->layout->pos) + TBL_CELL_DHORIZ == dat->layout->pos || + TBL_CELL_DOWN == dat->layout->pos) if (TBL_DATA_DATA == dat->pos && '\0' != *dat->string) - TBL_MSG(tbl, MANDOCERR_TBLIGNDATA, ln, sv); + mandoc_msg(MANDOCERR_TBLIGNDATA, + tbl->parse, ln, sv, NULL); return(1); } @@ -123,7 +148,6 @@ tbl_cdata(struct tbl_node *tbl, int ln, const char *p) pos = 0; dat = tbl->last_span->last; - dat->pos = TBL_DATA_DATA; if (p[pos] == 'T' && p[pos + 1] == '}') { pos += 2; @@ -139,6 +163,8 @@ tbl_cdata(struct tbl_node *tbl, int ln, const char *p) /* Fallthrough: T} is part of a word. */ } + dat->pos = TBL_DATA_DATA; + if (dat->string) { sz = strlen(p) + strlen(dat->string) + 2; dat->string = mandoc_realloc(dat->string, sz); @@ -147,9 +173,36 @@ tbl_cdata(struct tbl_node *tbl, int ln, const char *p) } else dat->string = mandoc_strdup(p); + if (TBL_CELL_DOWN == dat->layout->pos) + mandoc_msg(MANDOCERR_TBLIGNDATA, + tbl->parse, ln, pos, NULL); + return(0); } +static struct tbl_span * +newspan(struct tbl_node *tbl, int line, struct tbl_row *rp) +{ + struct tbl_span *dp; + + dp = mandoc_calloc(1, sizeof(struct tbl_span)); + dp->line = line; + dp->tbl = &tbl->opts; + dp->layout = rp; + dp->head = tbl->first_head; + + if (tbl->last_span) { + tbl->last_span->next = dp; + tbl->last_span = dp; + } else { + tbl->last_span = tbl->first_span = dp; + tbl->current_span = NULL; + dp->flags |= TBL_SPAN_FIRST; + } + + return(dp); +} + int tbl_data(struct tbl_node *tbl, int ln, const char *p) { @@ -160,7 +213,7 @@ tbl_data(struct tbl_node *tbl, int ln, const char *p) pos = 0; if ('\0' == p[pos]) { - TBL_MSG(tbl, MANDOCERR_TBL, ln, pos); + mandoc_msg(MANDOCERR_TBL, tbl->parse, ln, pos, NULL); return(0); } @@ -170,33 +223,38 @@ tbl_data(struct tbl_node *tbl, int ln, const char *p) * If there's no last parsed span, use the first row. Lastly, * if the last span was a horizontal line, use the same layout * (it doesn't "consume" the layout). - * - * In the end, this can be NULL! */ if (tbl->last_span) { assert(tbl->last_span->layout); - if (tbl->last_span->pos == TBL_SPAN_DATA) - rp = tbl->last_span->layout->next; - else + if (tbl->last_span->pos == TBL_SPAN_DATA) { + for (rp = tbl->last_span->layout->next; + rp && rp->first; rp = rp->next) { + switch (rp->first->pos) { + case (TBL_CELL_HORIZ): + dp = newspan(tbl, ln, rp); + dp->pos = TBL_SPAN_HORIZ; + continue; + case (TBL_CELL_DHORIZ): + dp = newspan(tbl, ln, rp); + dp->pos = TBL_SPAN_DHORIZ; + continue; + default: + break; + } + break; + } + } else rp = tbl->last_span->layout; + if (NULL == rp) rp = tbl->last_span->layout; } else rp = tbl->first_row; - dp = mandoc_calloc(1, sizeof(struct tbl_span)); - dp->tbl = &tbl->opts; - dp->layout = rp; - dp->head = tbl->first_head; + assert(rp); - if (tbl->last_span) { - tbl->last_span->next = dp; - tbl->last_span = dp; - } else { - tbl->last_span = tbl->first_span = dp; - dp->flags |= TBL_SPAN_FIRST; - } + dp = newspan(tbl, ln, rp); if ( ! strcmp(p, "_")) { dp->pos = TBL_SPAN_HORIZ; diff --git a/external/bsd/mdocml/dist/tbl_html.c b/external/bsd/mdocml/dist/tbl_html.c index 85c669895..89da1cc48 100644 --- a/external/bsd/mdocml/dist/tbl_html.c +++ b/external/bsd/mdocml/dist/tbl_html.c @@ -1,6 +1,6 @@ -/* $Vendor-Id: tbl_html.c,v 1.5 2011/01/06 12:31:39 kristaps Exp $ */ +/* $Vendor-Id: tbl_html.c,v 1.9 2011/09/18 14:14:15 schwarze Exp $ */ /* - * Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se> + * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -27,6 +27,7 @@ #include "out.h" #include "html.h" +static void html_tblopen(struct html *, const struct tbl_span *); static size_t html_tbl_len(size_t, void *); static size_t html_tbl_strlen(const char *, void *); @@ -46,81 +47,105 @@ html_tbl_strlen(const char *p, void *arg) return(strlen(p)); } -void -print_tbl(struct html *h, const struct tbl_span *sp) +static void +html_tblopen(struct html *h, const struct tbl_span *sp) { const struct tbl_head *hp; - const struct tbl_dat *dp; - struct tag *tt; struct htmlpair tag; struct roffsu su; struct roffcol *col; - /* Inhibit printing of spaces: we do padding ourselves. */ - - h->flags |= HTML_NONOSPACE; - h->flags |= HTML_NOSPACE; - - /* First pass: calculate widths. */ - if (TBL_SPAN_FIRST & sp->flags) { h->tbl.len = html_tbl_len; h->tbl.slen = html_tbl_strlen; tblcalc(&h->tbl, sp); } + assert(NULL == h->tblt); + PAIR_CLASS_INIT(&tag, "tbl"); + h->tblt = print_otag(h, TAG_TABLE, 1, &tag); + + for (hp = sp->head; hp; hp = hp->next) { + bufinit(h); + col = &h->tbl.cols[hp->ident]; + SCALE_HS_INIT(&su, col->width); + bufcat_su(h, "width", &su); + PAIR_STYLE_INIT(&tag, h); + print_otag(h, TAG_COL, 1, &tag); + } + + print_otag(h, TAG_TBODY, 0, NULL); +} + +void +print_tblclose(struct html *h) +{ + + assert(h->tblt); + print_tagq(h, h->tblt); + h->tblt = NULL; +} + +void +print_tbl(struct html *h, const struct tbl_span *sp) +{ + const struct tbl_head *hp; + const struct tbl_dat *dp; + struct htmlpair tag; + struct tag *tt; + + /* Inhibit printing of spaces: we do padding ourselves. */ + + if (NULL == h->tblt) + html_tblopen(h, sp); + + assert(h->tblt); + + h->flags |= HTML_NONOSPACE; + h->flags |= HTML_NOSPACE; + + tt = print_otag(h, TAG_TR, 0, NULL); + switch (sp->pos) { case (TBL_SPAN_HORIZ): /* FALLTHROUGH */ case (TBL_SPAN_DHORIZ): + PAIR_INIT(&tag, ATTR_COLSPAN, "0"); + print_otag(h, TAG_TD, 1, &tag); break; default: - PAIR_CLASS_INIT(&tag, "tbl"); - print_otag(h, TAG_TABLE, 1, &tag); - print_otag(h, TAG_TR, 0, NULL); - - /* Iterate over template headers. */ - dp = sp->first; for (hp = sp->head; hp; hp = hp->next) { + print_stagq(h, tt); + print_otag(h, TAG_TD, 0, NULL); + switch (hp->pos) { case (TBL_HEAD_VERT): /* FALLTHROUGH */ case (TBL_HEAD_DVERT): continue; case (TBL_HEAD_DATA): + if (NULL == dp) + break; + if (TBL_CELL_DOWN != dp->layout->pos) + if (dp->string) + print_text(h, dp->string); + dp = dp->next; break; } - - /* - * For the time being, use the simplest possible - * table styling: setting the widths of data - * columns. - */ - - col = &h->tbl.cols[hp->ident]; - SCALE_HS_INIT(&su, col->width); - bufcat_su(h, "width", &su); - PAIR_STYLE_INIT(&tag, h); - tt = print_otag(h, TAG_TD, 1, &tag); - - if (dp && dp->string) - print_text(h, dp->string); - if (dp) - dp = dp->next; - - print_tagq(h, tt); } break; } - h->flags &= ~HTML_NONOSPACE; + print_tagq(h, tt); - /* Close out column specifiers on the last span. */ + h->flags &= ~HTML_NONOSPACE; if (TBL_SPAN_LAST & sp->flags) { assert(h->tbl.cols); free(h->tbl.cols); h->tbl.cols = NULL; + print_tblclose(h); } + } diff --git a/external/bsd/mdocml/dist/tbl_layout.c b/external/bsd/mdocml/dist/tbl_layout.c index 6dea8418d..cac5362a4 100644 --- a/external/bsd/mdocml/dist/tbl_layout.c +++ b/external/bsd/mdocml/dist/tbl_layout.c @@ -1,6 +1,6 @@ -/* $Vendor-Id: tbl_layout.c,v 1.13 2011/01/09 05:38:23 joerg Exp $ */ +/* $Vendor-Id: tbl_layout.c,v 1.22 2011/09/18 14:14:15 schwarze Exp $ */ /* - * Copyright (c) 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -14,6 +14,10 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include <assert.h> #include <ctype.h> #include <stdlib.h> @@ -68,6 +72,23 @@ mods(struct tbl_node *tbl, struct tbl_cell *cp, char buf[5]; int i; + /* Not all types accept modifiers. */ + + switch (cp->pos) { + case (TBL_CELL_DOWN): + /* FALLTHROUGH */ + case (TBL_CELL_HORIZ): + /* FALLTHROUGH */ + case (TBL_CELL_DHORIZ): + /* FALLTHROUGH */ + case (TBL_CELL_VERT): + /* FALLTHROUGH */ + case (TBL_CELL_DVERT): + return(1); + default: + break; + } + mod: /* * XXX: since, at least for now, modifiers are non-conflicting @@ -100,7 +121,8 @@ mod: (*pos)++; goto mod; } - TBL_MSG(tbl, MANDOCERR_TBLLAYOUT, ln, *pos); + mandoc_msg(MANDOCERR_TBLLAYOUT, + tbl->parse, ln, *pos, NULL); return(0); } @@ -117,12 +139,13 @@ mod: /* No greater than 4 digits. */ if (4 == i) { - TBL_MSG(tbl, MANDOCERR_TBLLAYOUT, ln, *pos); + mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse, + ln, *pos, NULL); return(0); } *pos += i; - cp->spacing = atoi(buf); + cp->spacing = (size_t)atoi(buf); goto mod; /* NOTREACHED */ @@ -150,28 +173,40 @@ mod: goto mod; case ('f'): break; + case ('r'): + /* FALLTHROUGH */ case ('b'): /* FALLTHROUGH */ case ('i'): (*pos)--; break; default: - TBL_MSG(tbl, MANDOCERR_TBLLAYOUT, ln, *pos - 1); + mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse, + ln, *pos - 1, NULL); return(0); } switch (tolower((unsigned char)p[(*pos)++])) { + case ('3'): + /* FALLTHROUGH */ case ('b'): cp->flags |= TBL_CELL_BOLD; goto mod; + case ('2'): + /* FALLTHROUGH */ case ('i'): cp->flags |= TBL_CELL_ITALIC; goto mod; + case ('1'): + /* FALLTHROUGH */ + case ('r'): + goto mod; default: break; } - TBL_MSG(tbl, MANDOCERR_TBLLAYOUT, ln, *pos - 1); + mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse, + ln, *pos - 1, NULL); return(0); } @@ -189,7 +224,8 @@ cell(struct tbl_node *tbl, struct tbl_row *rp, break; if (KEYS_MAX == i) { - TBL_MSG(tbl, MANDOCERR_TBLLAYOUT, ln, *pos); + mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse, + ln, *pos, NULL); return(0); } @@ -197,11 +233,38 @@ cell(struct tbl_node *tbl, struct tbl_row *rp, /* * If a span cell is found first, raise a warning and abort the - * parse. FIXME: recover from this somehow? + * parse. If a span cell is found and the last layout element + * isn't a "normal" layout, bail. + * + * FIXME: recover from this somehow? */ - if (NULL == rp->first && TBL_CELL_SPAN == c) { - TBL_MSG(tbl, MANDOCERR_TBLLAYOUT, ln, *pos); + if (TBL_CELL_SPAN == c) { + if (NULL == rp->first) { + mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse, + ln, *pos, NULL); + return(0); + } else if (rp->last) + switch (rp->last->pos) { + case (TBL_CELL_VERT): + case (TBL_CELL_DVERT): + case (TBL_CELL_HORIZ): + case (TBL_CELL_DHORIZ): + mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse, + ln, *pos, NULL); + return(0); + default: + break; + } + } + + /* + * If a vertical spanner is found, we may not be in the first + * row. + */ + + if (TBL_CELL_DOWN == c && rp == tbl->first_row) { + mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse, ln, *pos, NULL); return(0); } @@ -219,7 +282,7 @@ cell(struct tbl_node *tbl, struct tbl_row *rp, if (rp->last && (TBL_CELL_VERT == c || TBL_CELL_DVERT == c) && (TBL_CELL_VERT == rp->last->pos || TBL_CELL_DVERT == rp->last->pos)) { - TBL_MSG(tbl, MANDOCERR_TBLLAYOUT, ln, *pos - 1); + mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse, ln, *pos - 1, NULL); return(0); } @@ -260,7 +323,8 @@ cell: if ('.' == p[*pos]) { tbl->part = TBL_PART_DATA; if (NULL == tbl->first_row) - TBL_MSG(tbl, MANDOCERR_TBLNOLAYOUT, ln, *pos); + mandoc_msg(MANDOCERR_TBLNOLAYOUT, tbl->parse, + ln, *pos, NULL); (*pos)++; return; } @@ -390,19 +454,19 @@ cell_alloc(struct tbl_node *tbl, struct tbl_row *rp, enum tbl_cellt pos) } static void -head_adjust(const struct tbl_cell *cell, struct tbl_head *head) +head_adjust(const struct tbl_cell *cellp, struct tbl_head *head) { - if (TBL_CELL_VERT != cell->pos && - TBL_CELL_DVERT != cell->pos) { + if (TBL_CELL_VERT != cellp->pos && + TBL_CELL_DVERT != cellp->pos) { head->pos = TBL_HEAD_DATA; return; } - if (TBL_CELL_VERT == cell->pos) + if (TBL_CELL_VERT == cellp->pos) if (TBL_HEAD_DVERT != head->pos) head->pos = TBL_HEAD_VERT; - if (TBL_CELL_DVERT == cell->pos) + if (TBL_CELL_DVERT == cellp->pos) head->pos = TBL_HEAD_DVERT; } diff --git a/external/bsd/mdocml/dist/tbl_opts.c b/external/bsd/mdocml/dist/tbl_opts.c index ff32bcc49..7d1aba910 100644 --- a/external/bsd/mdocml/dist/tbl_opts.c +++ b/external/bsd/mdocml/dist/tbl_opts.c @@ -1,6 +1,6 @@ -/* $Vendor-Id: tbl_opts.c,v 1.8 2011/01/09 05:38:23 joerg Exp $ */ +/* $Vendor-Id: tbl_opts.c,v 1.12 2011/09/18 14:14:15 schwarze Exp $ */ /* - * Copyright (c) 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -14,12 +14,17 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include <ctype.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include "mandoc.h" +#include "libmandoc.h" #include "libroff.h" enum tbl_ident { @@ -88,7 +93,8 @@ arg(struct tbl_node *tbl, int ln, const char *p, int *pos, enum tbl_ident key) /* Arguments always begin with a parenthesis. */ if ('(' != p[*pos]) { - TBL_MSG(tbl, MANDOCERR_TBL, ln, *pos); + mandoc_msg(MANDOCERR_TBL, tbl->parse, + ln, *pos, NULL); return(0); } @@ -103,12 +109,14 @@ arg(struct tbl_node *tbl, int ln, const char *p, int *pos, enum tbl_ident key) switch (key) { case (KEY_DELIM): if ('\0' == p[(*pos)++]) { - TBL_MSG(tbl, MANDOCERR_TBL, ln, *pos - 1); + mandoc_msg(MANDOCERR_TBL, tbl->parse, + ln, *pos - 1, NULL); return(0); } if ('\0' == p[(*pos)++]) { - TBL_MSG(tbl, MANDOCERR_TBL, ln, *pos - 1); + mandoc_msg(MANDOCERR_TBL, tbl->parse, + ln, *pos - 1, NULL); return(0); } break; @@ -116,7 +124,8 @@ arg(struct tbl_node *tbl, int ln, const char *p, int *pos, enum tbl_ident key) if ('\0' != (tbl->opts.tab = p[(*pos)++])) break; - TBL_MSG(tbl, MANDOCERR_TBL, ln, *pos - 1); + mandoc_msg(MANDOCERR_TBL, tbl->parse, + ln, *pos - 1, NULL); return(0); case (KEY_LINESIZE): for (i = 0; i < KEY_MAXNUMSZ && p[*pos]; i++, (*pos)++) { @@ -131,13 +140,14 @@ arg(struct tbl_node *tbl, int ln, const char *p, int *pos, enum tbl_ident key) break; } - (*tbl->msg)(MANDOCERR_TBL, tbl->data, ln, *pos, NULL); + mandoc_msg(MANDOCERR_TBL, tbl->parse, ln, *pos, NULL); return(0); case (KEY_DPOINT): if ('\0' != (tbl->opts.decimal = p[(*pos)++])) break; - TBL_MSG(tbl, MANDOCERR_TBL, ln, *pos - 1); + mandoc_msg(MANDOCERR_TBL, tbl->parse, + ln, *pos - 1, NULL); return(0); default: abort(); @@ -149,7 +159,7 @@ arg(struct tbl_node *tbl, int ln, const char *p, int *pos, enum tbl_ident key) if (')' == p[(*pos)++]) return(1); - TBL_MSG(tbl, MANDOCERR_TBL, ln, *pos - 1); + mandoc_msg(MANDOCERR_TBL, tbl->parse, ln, *pos - 1, NULL); return(0); } @@ -188,7 +198,7 @@ again: /* /* Copy up to first non-alpha character. */ for (sv = *pos, i = 0; i < KEY_MAXNAME; i++, (*pos)++) { - buf[i] = tolower((unsigned char)p[*pos]); + buf[i] = (char)tolower((unsigned char)p[*pos]); if ( ! isalpha((unsigned char)buf[i])) break; } @@ -196,7 +206,7 @@ again: /* /* Exit if buffer is empty (or overrun). */ if (KEY_MAXNAME == i || 0 == i) { - TBL_MSG(tbl, MANDOCERR_TBL, ln, *pos); + mandoc_msg(MANDOCERR_TBL, tbl->parse, ln, *pos, NULL); return; } @@ -235,7 +245,7 @@ again: /* */ if (KEY_MAXKEYS == i) - TBL_MSG(tbl, MANDOCERR_TBLOPT, ln, sv); + mandoc_msg(MANDOCERR_TBLOPT, tbl->parse, ln, sv, NULL); goto again; /* NOTREACHED */ diff --git a/external/bsd/mdocml/dist/tbl_term.c b/external/bsd/mdocml/dist/tbl_term.c index 7607adef2..815aa4da6 100644 --- a/external/bsd/mdocml/dist/tbl_term.c +++ b/external/bsd/mdocml/dist/tbl_term.c @@ -1,6 +1,7 @@ -/* $Vendor-Id: tbl_term.c,v 1.13 2011/01/07 14:59:52 kristaps Exp $ */ +/* $Vendor-Id: tbl_term.c,v 1.21 2011/09/20 23:05:49 schwarze Exp $ */ /* - * Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se> + * Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -27,23 +28,20 @@ #include "out.h" #include "term.h" -/* FIXME: `n' modifier doesn't always do the right thing. */ -/* FIXME: `n' modifier doesn't use the cell-spacing buffer. */ - static size_t term_tbl_len(size_t, void *); static size_t term_tbl_strlen(const char *, void *); static void tbl_char(struct termp *, char, size_t); static void tbl_data(struct termp *, const struct tbl *, const struct tbl_dat *, const struct roffcol *); -static void tbl_hframe(struct termp *, const struct tbl_span *); +static size_t tbl_rulewidth(struct termp *, const struct tbl_head *); +static void tbl_hframe(struct termp *, const struct tbl_span *, int); static void tbl_literal(struct termp *, const struct tbl_dat *, const struct roffcol *); static void tbl_number(struct termp *, const struct tbl *, const struct tbl_dat *, const struct roffcol *); static void tbl_hrule(struct termp *, const struct tbl_span *); -static void tbl_vframe(struct termp *, const struct tbl *); static void tbl_vrule(struct termp *, const struct tbl_head *); @@ -67,6 +65,7 @@ term_tbl(struct termp *tp, const struct tbl_span *sp) const struct tbl_head *hp; const struct tbl_dat *dp; struct roffcol *col; + int spans; size_t rmargin, maxrmargin; rmargin = tp->rmargin; @@ -96,12 +95,19 @@ term_tbl(struct termp *tp, const struct tbl_span *sp) /* Horizontal frame at the start of boxed tables. */ - if (TBL_SPAN_FIRST & sp->flags) - tbl_hframe(tp, sp); + if (TBL_SPAN_FIRST & sp->flags) { + if (TBL_OPT_DBOX & sp->tbl->opts) + tbl_hframe(tp, sp, 1); + if (TBL_OPT_DBOX & sp->tbl->opts || + TBL_OPT_BOX & sp->tbl->opts) + tbl_hframe(tp, sp, 0); + } /* Vertical frame at the start of each row. */ - tbl_vframe(tp, sp->tbl); + if (TBL_OPT_BOX & sp->tbl->opts || TBL_OPT_DBOX & sp->tbl->opts) + term_word(tp, TBL_SPAN_HORIZ == sp->pos || + TBL_SPAN_DHORIZ == sp->pos ? "+" : "|"); /* * Now print the actual data itself depending on the span type. @@ -118,28 +124,70 @@ term_tbl(struct termp *tp, const struct tbl_span *sp) case (TBL_SPAN_DATA): /* Iterate over template headers. */ dp = sp->first; + spans = 0; for (hp = sp->head; hp; hp = hp->next) { + /* + * If the current data header is invoked during + * a spanner ("spans" > 0), don't emit anything + * at all. + */ switch (hp->pos) { case (TBL_HEAD_VERT): /* FALLTHROUGH */ case (TBL_HEAD_DVERT): - tbl_vrule(tp, hp); + if (spans <= 0) + tbl_vrule(tp, hp); continue; case (TBL_HEAD_DATA): break; } + if (--spans >= 0) + continue; + + /* + * All cells get a leading blank, except the + * first one and those after double rulers. + */ + + if (hp->prev && TBL_HEAD_DVERT != hp->prev->pos) + tbl_char(tp, ASCII_NBRSP, 1); + col = &tp->tbl.cols[hp->ident]; tbl_data(tp, sp->tbl, dp, col); - /* Go to the next data cell. */ - if (dp) + /* No trailing blanks. */ + + if (NULL == hp->next) + break; + + /* + * Add another blank between cells, + * or two when there is no vertical ruler. + */ + + tbl_char(tp, ASCII_NBRSP, + TBL_HEAD_VERT == hp->next->pos || + TBL_HEAD_DVERT == hp->next->pos ? 1 : 2); + + /* + * Go to the next data cell and assign the + * number of subsequent spans, if applicable. + */ + + if (dp) { + spans = dp->spans; dp = dp->next; + } } break; } - tbl_vframe(tp, sp->tbl); + /* Vertical frame at the end of each row. */ + + if (TBL_OPT_BOX & sp->tbl->opts || TBL_OPT_DBOX & sp->tbl->opts) + term_word(tp, TBL_SPAN_HORIZ == sp->pos || + TBL_SPAN_DHORIZ == sp->pos ? "+" : " |"); term_flushln(tp); /* @@ -148,7 +196,11 @@ term_tbl(struct termp *tp, const struct tbl_span *sp) */ if (TBL_SPAN_LAST & sp->flags) { - tbl_hframe(tp, sp); + if (TBL_OPT_DBOX & sp->tbl->opts || + TBL_OPT_BOX & sp->tbl->opts) + tbl_hframe(tp, sp, 0); + if (TBL_OPT_DBOX & sp->tbl->opts) + tbl_hframe(tp, sp, 1); assert(tp->tbl.cols); free(tp->tbl.cols); tp->tbl.cols = NULL; @@ -160,84 +212,66 @@ term_tbl(struct termp *tp, const struct tbl_span *sp) } +/* + * Horizontal rules extend across the entire table. + * Calculate the width by iterating over columns. + */ +static size_t +tbl_rulewidth(struct termp *tp, const struct tbl_head *hp) +{ + size_t width; + + width = tp->tbl.cols[hp->ident].width; + if (TBL_HEAD_DATA == hp->pos) { + /* Account for leading blanks. */ + if (hp->prev && TBL_HEAD_DVERT != hp->prev->pos) + width++; + /* Account for trailing blanks. */ + width++; + if (hp->next && + TBL_HEAD_VERT != hp->next->pos && + TBL_HEAD_DVERT != hp->next->pos) + width++; + } + return(width); +} + +/* + * Rules inside the table can be single or double + * and have crossings with vertical rules marked with pluses. + */ static void tbl_hrule(struct termp *tp, const struct tbl_span *sp) { const struct tbl_head *hp; char c; - size_t width; - - /* - * An hrule extends across the entire table and is demarked by a - * standalone `_' or whatnot in lieu of a table row. Spanning - * headers are marked by a `+', as are table boundaries. - */ c = '-'; if (TBL_SPAN_DHORIZ == sp->pos) c = '='; - /* FIXME: don't use `+' between data and a spanner! */ - - for (hp = sp->head; hp; hp = hp->next) { - width = tp->tbl.cols[hp->ident].width; - switch (hp->pos) { - case (TBL_HEAD_DATA): - tbl_char(tp, c, width); - break; - case (TBL_HEAD_DVERT): - tbl_char(tp, '+', width); - /* FALLTHROUGH */ - case (TBL_HEAD_VERT): - tbl_char(tp, '+', width); - break; - default: - abort(); - /* NOTREACHED */ - } - } + for (hp = sp->head; hp; hp = hp->next) + tbl_char(tp, + TBL_HEAD_DATA == hp->pos ? c : '+', + tbl_rulewidth(tp, hp)); } +/* + * Rules above and below the table are always single + * and have an additional plus at the beginning and end. + * For double frames, this function is called twice, + * and the outer one does not have crossings. + */ static void -tbl_hframe(struct termp *tp, const struct tbl_span *sp) +tbl_hframe(struct termp *tp, const struct tbl_span *sp, int outer) { const struct tbl_head *hp; - size_t width; - - if ( ! (TBL_OPT_BOX & sp->tbl->opts || - TBL_OPT_DBOX & sp->tbl->opts)) - return; - - /* - * Print out the horizontal part of a frame or double frame. A - * double frame has an unbroken `-' outer line the width of the - * table, bordered by `+'. The frame (or inner frame, in the - * case of the double frame) is a `-' bordered by `+' and broken - * by `+' whenever a span is encountered. - */ - - if (TBL_OPT_DBOX & sp->tbl->opts) { - term_word(tp, "+"); - for (hp = sp->head; hp; hp = hp->next) { - width = tp->tbl.cols[hp->ident].width; - tbl_char(tp, '-', width); - } - term_word(tp, "+"); - term_flushln(tp); - } term_word(tp, "+"); - for (hp = sp->head; hp; hp = hp->next) { - width = tp->tbl.cols[hp->ident].width; - switch (hp->pos) { - case (TBL_HEAD_DATA): - tbl_char(tp, '-', width); - break; - default: - tbl_char(tp, '+', width); - break; - } - } + for (hp = sp->head; hp; hp = hp->next) + tbl_char(tp, + outer || TBL_HEAD_DATA == hp->pos ? '-' : '+', + tbl_rulewidth(tp, hp)); term_word(tp, "+"); term_flushln(tp); } @@ -247,12 +281,12 @@ tbl_data(struct termp *tp, const struct tbl *tbl, const struct tbl_dat *dp, const struct roffcol *col) { - enum tbl_cellt pos; if (NULL == dp) { tbl_char(tp, ASCII_NBRSP, col->width); return; } + assert(dp->layout); switch (dp->pos) { case (TBL_DATA_NONE): @@ -272,9 +306,7 @@ tbl_data(struct termp *tp, const struct tbl *tbl, break; } - pos = dp && dp->layout ? dp->layout->pos : TBL_CELL_LEFT; - - switch (pos) { + switch (dp->layout->pos) { case (TBL_CELL_HORIZ): tbl_char(tp, '-', col->width); break; @@ -293,6 +325,9 @@ tbl_data(struct termp *tp, const struct tbl *tbl, case (TBL_CELL_NUMBER): tbl_number(tp, tbl, dp, col); break; + case (TBL_CELL_DOWN): + tbl_char(tp, ASCII_NBRSP, col->width); + break; default: abort(); /* NOTREACHED */ @@ -315,14 +350,6 @@ tbl_vrule(struct termp *tp, const struct tbl_head *hp) } } -static void -tbl_vframe(struct termp *tp, const struct tbl *tbl) -{ - - if (TBL_OPT_BOX & tbl->opts || TBL_OPT_DBOX & tbl->opts) - term_word(tp, "|"); -} - static void tbl_char(struct termp *tp, char c, size_t len) { @@ -342,39 +369,34 @@ static void tbl_literal(struct termp *tp, const struct tbl_dat *dp, const struct roffcol *col) { - size_t padl, padr, ssz; - enum tbl_cellt pos; - const char *str; + size_t len, padl, padr; - padl = padr = 0; + assert(dp->string); + len = term_strlen(tp, dp->string); + padr = col->width > len ? col->width - len : 0; + padl = 0; - pos = dp && dp->layout ? dp->layout->pos : TBL_CELL_LEFT; - str = dp && dp->string ? dp->string : ""; - - ssz = term_len(tp, 1); - - switch (pos) { + switch (dp->layout->pos) { case (TBL_CELL_LONG): - padl = ssz; - padr = col->width - term_strlen(tp, str) - ssz; + padl = term_len(tp, 1); + padr = padr > padl ? padr - padl : 0; break; case (TBL_CELL_CENTRE): - padl = col->width - term_strlen(tp, str); - if (padl % 2) - padr++; - padl /= 2; - padr += padl; + if (2 > padr) + break; + padl = padr / 2; + padr -= padl; break; case (TBL_CELL_RIGHT): - padl = col->width - term_strlen(tp, str); + padl = padr; + padr = 0; break; default: - padr = col->width - term_strlen(tp, str); break; } tbl_char(tp, ASCII_NBRSP, padl); - term_word(tp, str); + term_word(tp, dp->string); tbl_char(tp, ASCII_NBRSP, padr); } @@ -385,7 +407,6 @@ tbl_number(struct termp *tp, const struct tbl *tbl, { char *cp; char buf[2]; - const char *str; size_t sz, psz, ssz, d, padl; int i; @@ -394,32 +415,30 @@ tbl_number(struct termp *tp, const struct tbl *tbl, * and the maximum decimal; right-pad by the remaining amount. */ - str = dp && dp->string ? dp->string : ""; + assert(dp->string); - sz = term_strlen(tp, str); + sz = term_strlen(tp, dp->string); buf[0] = tbl->decimal; buf[1] = '\0'; psz = term_strlen(tp, buf); - if (NULL != (cp = strchr(str, tbl->decimal))) { + if (NULL != (cp = strrchr(dp->string, tbl->decimal))) { buf[1] = '\0'; - for (ssz = 0, i = 0; cp != &str[i]; i++) { - buf[0] = str[i]; + for (ssz = 0, i = 0; cp != &dp->string[i]; i++) { + buf[0] = dp->string[i]; ssz += term_strlen(tp, buf); } d = ssz + psz; } else d = sz + psz; - sz += term_len(tp, 2); - d += term_len(tp, 1); - padl = col->decimal - d; tbl_char(tp, ASCII_NBRSP, padl); - term_word(tp, str); - tbl_char(tp, ASCII_NBRSP, col->width - sz - padl); + term_word(tp, dp->string); + if (col->width > sz + padl) + tbl_char(tp, ASCII_NBRSP, col->width - sz - padl); } diff --git a/external/bsd/mdocml/dist/term.c b/external/bsd/mdocml/dist/term.c index c46b4c413..879df166a 100644 --- a/external/bsd/mdocml/dist/term.c +++ b/external/bsd/mdocml/dist/term.c @@ -1,7 +1,7 @@ -/* $Vendor-Id: term.c,v 1.176 2011/01/04 13:14:26 kristaps Exp $ */ +/* $Vendor-Id: term.c,v 1.201 2011/09/21 09:57:13 schwarze Exp $ */ /* - * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -29,18 +29,14 @@ #include <string.h> #include "mandoc.h" -#include "chars.h" #include "out.h" #include "term.h" #include "main.h" -static void spec(struct termp *, enum roffdeco, - const char *, size_t); -static void res(struct termp *, const char *, size_t); -static void bufferc(struct termp *, char); -static void adjbuf(struct termp *p, size_t); -static void encode(struct termp *, const char *, size_t); - +static void adjbuf(struct termp *p, int); +static void bufferc(struct termp *, char); +static void encode(struct termp *, const char *, size_t); +static void encode1(struct termp *, int); void term_free(struct termp *p) @@ -49,7 +45,7 @@ term_free(struct termp *p) if (p->buf) free(p->buf); if (p->symtab) - chars_free(p->symtab); + mchars_free(p->symtab); free(p); } @@ -74,23 +70,6 @@ term_end(struct termp *p) (*p->end)(p); } - -struct termp * -term_alloc(enum termenc enc) -{ - struct termp *p; - - p = calloc(1, sizeof(struct termp)); - if (NULL == p) { - perror(NULL); - exit((int)MANDOCLEVEL_SYSERR); - } - - p->enc = enc; - return(p); -} - - /* * Flush a line of text. A "line" is loosely defined as being something * that should be followed by a newline, regardless of whether it's @@ -100,22 +79,18 @@ term_alloc(enum termenc enc) * * The following flags may be specified: * - * - TERMP_NOLPAD: when beginning to write the line, don't left-pad the - * offset value. This is useful when doing columnar lists where the - * prior column has right-padded. - * * - TERMP_NOBREAK: this is the most important and is used when making - * columns. In short: don't print a newline and instead pad to the - * right margin. Used in conjunction with TERMP_NOLPAD. + * columns. In short: don't print a newline and instead expect the + * next call to do the padding up to the start of the next column. * - * - TERMP_TWOSPACE: when padding, make sure there are at least two - * space characters of padding. Otherwise, rather break the line. + * - TERMP_TWOSPACE: make sure there is room for at least two space + * characters of padding. Otherwise, rather break the line. * * - TERMP_DANGLE: don't newline when TERMP_NOBREAK is specified and * the line is overrun, and don't pad-right if it's underrun. * * - TERMP_HANG: like TERMP_DANGLE, but doesn't newline when - * overruning, instead save the position and continue at that point + * overrunning, instead save the position and continue at that point * when the next invocation. * * In-line line breaking: @@ -155,19 +130,20 @@ term_flushln(struct termp *p) bp = TERMP_NOBREAK & p->flags ? mmax : maxvis; /* - * Indent the first line of a paragraph. + * Calculate the required amount of padding. */ - vbl = p->flags & TERMP_NOLPAD ? (size_t)0 : p->offset; + vbl = p->offset + p->overstep > p->viscol ? + p->offset + p->overstep - p->viscol : 0; vis = vend = 0; i = 0; - while (i < (int)p->col) { + while (i < p->col) { /* * Handle literal tab characters: collapse all * subsequent tabs into a single huge set of spaces. */ - while (i < (int)p->col && '\t' == p->buf[i]) { + while (i < p->col && '\t' == p->buf[i]) { vend = (vis / p->tabwidth + 1) * p->tabwidth; vbl += vend - vis; vis = vend; @@ -181,7 +157,7 @@ term_flushln(struct termp *p) * space is printed according to regular spacing rules). */ - for (j = i, jhy = 0; j < (int)p->col; j++) { + for (j = i, jhy = 0; j < p->col; j++) { if ((j && ' ' == p->buf[j]) || '\t' == p->buf[j]) break; @@ -208,14 +184,12 @@ term_flushln(struct termp *p) if (vend > bp && 0 == jhy && vis > 0) { vend -= vis; (*p->endline)(p); + p->viscol = 0; if (TERMP_NOBREAK & p->flags) { - p->viscol = p->rmargin; - (*p->advance)(p, p->rmargin); + vbl = p->rmargin; vend += p->rmargin - p->offset; - } else { - p->viscol = 0; + } else vbl = p->offset; - } /* Remove the p->overstep width. */ @@ -224,7 +198,7 @@ term_flushln(struct termp *p) } /* Write out the [remaining] word. */ - for ( ; i < (int)p->col; i++) { + for ( ; i < p->col; i++) { if (vend > bp && jhy > 0 && i > jhy) break; if ('\t' == p->buf[i]) @@ -257,10 +231,14 @@ term_flushln(struct termp *p) if (ASCII_HYPH == p->buf[i]) { (*p->letter)(p, '-'); p->viscol += (*p->width)(p, '-'); - } else { - (*p->letter)(p, p->buf[i]); - p->viscol += (*p->width)(p, p->buf[i]); + continue; } + + (*p->letter)(p, p->buf[i]); + if (8 == p->buf[i]) + p->viscol -= (*p->width)(p, p->buf[i-1]); + else + p->viscol += (*p->width)(p, p->buf[i]); } vis = vend; } @@ -269,7 +247,8 @@ term_flushln(struct termp *p) * If there was trailing white space, it was not printed; * so reset the cursor position accordingly. */ - vis -= vbl; + if (vis) + vis -= vbl; p->col = 0; p->overstep = 0; @@ -294,25 +273,18 @@ term_flushln(struct termp *p) * move it one step LEFT and flag the rest of the line * to be longer. */ - if (p->overstep >= -1) { - assert((int)maxvis + p->overstep >= 0); - maxvis += (size_t)p->overstep; - } else + if (p->overstep < -1) p->overstep = 0; + return; } else if (TERMP_DANGLE & p->flags) return; - /* Right-pad. */ - if (maxvis > vis + + /* If the column was overrun, break the line. */ + if (maxvis <= vis + ((TERMP_TWOSPACE & p->flags) ? (*p->width)(p, ' ') : 0)) { - p->viscol += maxvis - vis; - (*p->advance)(p, maxvis - vis); - vis += (maxvis - vis); - } else { /* ...or newline break. */ (*p->endline)(p); - p->viscol = p->rmargin; - (*p->advance)(p, p->rmargin); + p->viscol = 0; } } @@ -327,12 +299,8 @@ term_newln(struct termp *p) { p->flags |= TERMP_NOSPACE; - if (0 == p->col && 0 == p->viscol) { - p->flags &= ~TERMP_NOLPAD; - return; - } - term_flushln(p); - p->flags &= ~TERMP_NOLPAD; + if (p->col || p->viscol) + term_flushln(p); } @@ -351,33 +319,6 @@ term_vspace(struct termp *p) (*p->endline)(p); } - -static void -spec(struct termp *p, enum roffdeco d, const char *word, size_t len) -{ - const char *rhs; - size_t sz; - - rhs = chars_spec2str(p->symtab, word, len, &sz); - if (rhs) - encode(p, rhs, sz); - else if (DECO_SSPECIAL == d) - encode(p, word, len); -} - - -static void -res(struct termp *p, const char *word, size_t len) -{ - const char *rhs; - size_t sz; - - rhs = chars_res2str(p->symtab, word, len, &sz); - if (rhs) - encode(p, rhs, sz); -} - - void term_fontlast(struct termp *p) { @@ -442,7 +383,6 @@ term_fontpop(struct termp *p) p->fonti--; } - /* * Handle pwords, partial words, which may be either a single word or a * phrase that cannot be broken down (such as a literal string). This @@ -451,35 +391,11 @@ term_fontpop(struct termp *p) void term_word(struct termp *p, const char *word) { - const char *sv, *seq; + const char *seq, *cp; + char c; + int sz, uc; size_t ssz; - enum roffdeco deco; - - sv = word; - - if (word[0] && '\0' == word[1]) - switch (word[0]) { - case('.'): - /* FALLTHROUGH */ - case(','): - /* FALLTHROUGH */ - case(';'): - /* FALLTHROUGH */ - case(':'): - /* FALLTHROUGH */ - case('?'): - /* FALLTHROUGH */ - case('!'): - /* FALLTHROUGH */ - case(')'): - /* FALLTHROUGH */ - case(']'): - if ( ! (TERMP_IGNDELIM & p->flags)) - p->flags |= TERMP_NOSPACE; - break; - default: - break; - } + enum mandoc_esc esc; if ( ! (TERMP_NOSPACE & p->flags)) { if ( ! (TERMP_KEEP & p->flags)) { @@ -499,65 +415,79 @@ term_word(struct termp *p, const char *word) p->flags &= ~(TERMP_SENTENCE | TERMP_IGNDELIM); - while (*word) { + while ('\0' != *word) { if ((ssz = strcspn(word, "\\")) > 0) encode(p, word, ssz); - word += ssz; + word += (int)ssz; if ('\\' != *word) continue; - seq = ++word; - word += a2roffdeco(&deco, &seq, &ssz); + word++; + esc = mandoc_escape(&word, &seq, &sz); + if (ESCAPE_ERROR == esc) + break; - switch (deco) { - case (DECO_RESERVED): - res(p, seq, ssz); + if (TERMENC_ASCII != p->enc) + switch (esc) { + case (ESCAPE_UNICODE): + uc = mchars_num2uc(seq + 1, sz - 1); + if ('\0' == uc) + break; + encode1(p, uc); + continue; + case (ESCAPE_SPECIAL): + uc = mchars_spec2cp(p->symtab, seq, sz); + if (uc <= 0) + break; + encode1(p, uc); + continue; + default: + break; + } + + switch (esc) { + case (ESCAPE_UNICODE): + encode1(p, '?'); break; - case (DECO_SPECIAL): - /* FALLTHROUGH */ - case (DECO_SSPECIAL): - spec(p, deco, seq, ssz); + case (ESCAPE_NUMBERED): + c = mchars_num2char(seq, sz); + if ('\0' != c) + encode(p, &c, 1); break; - case (DECO_BOLD): + case (ESCAPE_SPECIAL): + cp = mchars_spec2str(p->symtab, seq, sz, &ssz); + if (NULL != cp) + encode(p, cp, ssz); + else if (1 == ssz) + encode(p, seq, sz); + break; + case (ESCAPE_FONTBOLD): term_fontrepl(p, TERMFONT_BOLD); break; - case (DECO_ITALIC): + case (ESCAPE_FONTITALIC): term_fontrepl(p, TERMFONT_UNDER); break; - case (DECO_ROMAN): + case (ESCAPE_FONT): + /* FALLTHROUGH */ + case (ESCAPE_FONTROMAN): term_fontrepl(p, TERMFONT_NONE); break; - case (DECO_PREVIOUS): + case (ESCAPE_FONTPREV): term_fontlast(p); break; + case (ESCAPE_NOSPACE): + if ('\0' == *word) + p->flags |= TERMP_NOSPACE; + break; default: break; } - - if (DECO_NOSPACE == deco && '\0' == *word) - p->flags |= TERMP_NOSPACE; } - - /* - * Note that we don't process the pipe: the parser sees it as - * punctuation, but we don't in terms of typography. - */ - if (sv[0] && '\0' == sv[1]) - switch (sv[0]) { - case('('): - /* FALLTHROUGH */ - case('['): - p->flags |= TERMP_NOSPACE; - break; - default: - break; - } } - static void -adjbuf(struct termp *p, size_t sz) +adjbuf(struct termp *p, int sz) { if (0 == p->maxcols) @@ -565,14 +495,10 @@ adjbuf(struct termp *p, size_t sz) while (sz >= p->maxcols) p->maxcols <<= 2; - p->buf = realloc(p->buf, p->maxcols); - if (NULL == p->buf) { - perror(NULL); - exit((int)MANDOCLEVEL_SYSERR); - } + p->buf = mandoc_realloc + (p->buf, sizeof(int) * (size_t)p->maxcols); } - static void bufferc(struct termp *p, char c) { @@ -580,15 +506,44 @@ bufferc(struct termp *p, char c) if (p->col + 1 >= p->maxcols) adjbuf(p, p->col + 1); - p->buf[(int)p->col++] = c; + p->buf[p->col++] = c; } +/* + * See encode(). + * Do this for a single (probably unicode) value. + * Does not check for non-decorated glyphs. + */ +static void +encode1(struct termp *p, int c) +{ + enum termfont f; + + if (p->col + 4 >= p->maxcols) + adjbuf(p, p->col + 4); + + f = term_fonttop(p); + + if (TERMFONT_NONE == f) { + p->buf[p->col++] = c; + return; + } else if (TERMFONT_UNDER == f) { + p->buf[p->col++] = '_'; + } else + p->buf[p->col++] = c; + + p->buf[p->col++] = 8; + p->buf[p->col++] = c; +} static void encode(struct termp *p, const char *word, size_t sz) { enum termfont f; - int i; + int i, len; + + /* LINTED */ + len = sz; /* * Encode and buffer a string of characters. If the current @@ -597,35 +552,37 @@ encode(struct termp *p, const char *word, size_t sz) */ if (TERMFONT_NONE == (f = term_fonttop(p))) { - if (p->col + sz >= p->maxcols) - adjbuf(p, p->col + sz); - memcpy(&p->buf[(int)p->col], word, sz); - p->col += sz; + if (p->col + len >= p->maxcols) + adjbuf(p, p->col + len); + for (i = 0; i < len; i++) + p->buf[p->col++] = word[i]; return; } /* Pre-buffer, assuming worst-case. */ - if (p->col + 1 + (sz * 3) >= p->maxcols) - adjbuf(p, p->col + 1 + (sz * 3)); + if (p->col + 1 + (len * 3) >= p->maxcols) + adjbuf(p, p->col + 1 + (len * 3)); - for (i = 0; i < (int)sz; i++) { - if ( ! isgraph((u_char)word[i])) { - p->buf[(int)p->col++] = word[i]; + for (i = 0; i < len; i++) { + if (ASCII_HYPH != word[i] && + ! isgraph((unsigned char)word[i])) { + p->buf[p->col++] = word[i]; continue; } if (TERMFONT_UNDER == f) - p->buf[(int)p->col++] = '_'; + p->buf[p->col++] = '_'; + else if (ASCII_HYPH == word[i]) + p->buf[p->col++] = '-'; else - p->buf[(int)p->col++] = word[i]; + p->buf[p->col++] = word[i]; - p->buf[(int)p->col++] = 8; - p->buf[(int)p->col++] = word[i]; + p->buf[p->col++] = 8; + p->buf[p->col++] = word[i]; } } - size_t term_len(const struct termp *p, size_t sz) { @@ -637,59 +594,99 @@ term_len(const struct termp *p, size_t sz) size_t term_strlen(const struct termp *p, const char *cp) { - size_t sz, ssz, rsz, i; - enum roffdeco d; + size_t sz, rsz, i; + int ssz, c; const char *seq, *rhs; + enum mandoc_esc esc; + static const char rej[] = { '\\', ASCII_HYPH, ASCII_NBRSP, '\0' }; - for (sz = 0; '\0' != *cp; ) - /* - * Account for escaped sequences within string length - * calculations. This follows the logic in term_word() - * as we must calculate the width of produced strings. - */ - if ('\\' == *cp) { - seq = ++cp; - cp += a2roffdeco(&d, &seq, &ssz); + /* + * Account for escaped sequences within string length + * calculations. This follows the logic in term_word() as we + * must calculate the width of produced strings. + */ - switch (d) { - case (DECO_RESERVED): - rhs = chars_res2str - (p->symtab, seq, ssz, &rsz); + sz = 0; + while ('\0' != *cp) { + rsz = strcspn(cp, rej); + for (i = 0; i < rsz; i++) + sz += (*p->width)(p, *cp++); + + c = 0; + switch (*cp) { + case ('\\'): + cp++; + esc = mandoc_escape(&cp, &seq, &ssz); + if (ESCAPE_ERROR == esc) + return(sz); + + if (TERMENC_ASCII != p->enc) + switch (esc) { + case (ESCAPE_UNICODE): + c = mchars_num2uc + (seq + 1, ssz - 1); + if ('\0' == c) + break; + sz += (*p->width)(p, c); + continue; + case (ESCAPE_SPECIAL): + c = mchars_spec2cp + (p->symtab, seq, ssz); + if (c <= 0) + break; + sz += (*p->width)(p, c); + continue; + default: + break; + } + + rhs = NULL; + + switch (esc) { + case (ESCAPE_UNICODE): + sz += (*p->width)(p, '?'); break; - case (DECO_SPECIAL): - /* FALLTHROUGH */ - case (DECO_SSPECIAL): - rhs = chars_spec2str + case (ESCAPE_NUMBERED): + c = mchars_num2char(seq, ssz); + if ('\0' != c) + sz += (*p->width)(p, c); + break; + case (ESCAPE_SPECIAL): + rhs = mchars_spec2str (p->symtab, seq, ssz, &rsz); - /* Allow for one-char escapes. */ - if (DECO_SSPECIAL != d || rhs) + if (ssz != 1 || rhs) break; rhs = seq; rsz = ssz; break; default: - rhs = NULL; break; } - if (rhs) - for (i = 0; i < rsz; i++) - sz += (*p->width)(p, *rhs++); - } else if (ASCII_NBRSP == *cp) { + if (NULL == rhs) + break; + + for (i = 0; i < rsz; i++) + sz += (*p->width)(p, *rhs++); + break; + case (ASCII_NBRSP): sz += (*p->width)(p, ' '); cp++; - } else if (ASCII_HYPH == *cp) { + break; + case (ASCII_HYPH): sz += (*p->width)(p, '-'); cp++; - } else - sz += (*p->width)(p, *cp++); + break; + default: + break; + } + } return(sz); } - /* ARGSUSED */ size_t term_vspan(const struct termp *p, const struct roffsu *su) @@ -726,7 +723,6 @@ term_vspan(const struct termp *p, const struct roffsu *su) r); } - size_t term_hspan(const struct termp *p, const struct roffsu *su) { diff --git a/external/bsd/mdocml/dist/term.h b/external/bsd/mdocml/dist/term.h index 9edca2212..7ea40b51b 100644 --- a/external/bsd/mdocml/dist/term.h +++ b/external/bsd/mdocml/dist/term.h @@ -1,6 +1,6 @@ -/* $Vendor-Id: term.h,v 1.79 2011/01/05 15:37:23 kristaps Exp $ */ +/* $Vendor-Id: term.h,v 1.90 2011/12/04 23:10:52 schwarze Exp $ */ /* - * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -22,7 +22,9 @@ __BEGIN_DECLS struct termp; enum termenc { - TERMENC_ASCII + TERMENC_ASCII, + TERMENC_LOCALE, + TERMENC_UTF8 }; enum termtype { @@ -42,35 +44,6 @@ enum termfont { typedef void (*term_margin)(struct termp *, const void *); -struct termp_ps { - int flags; -#define PS_INLINE (1 << 0) /* we're in a word */ -#define PS_MARGINS (1 << 1) /* we're in the margins */ -#define PS_NEWPAGE (1 << 2) /* new page, no words yet */ - size_t pscol; /* visible column (AFM units) */ - size_t psrow; /* visible row (AFM units) */ - char *psmarg; /* margin buf */ - size_t psmargsz; /* margin buf size */ - size_t psmargcur; /* cur index in margin buf */ - char last; /* character buffer */ - enum termfont lastf; /* last set font */ - size_t scale; /* font scaling factor */ - size_t pages; /* number of pages shown */ - size_t lineheight; /* line height (AFM units) */ - size_t top; /* body top (AFM units) */ - size_t bottom; /* body bottom (AFM units) */ - size_t height; /* page height (AFM units */ - size_t width; /* page width (AFM units) */ - size_t left; /* body left (AFM units) */ - size_t header; /* header pos (AFM units) */ - size_t footer; /* footer pos (AFM units) */ - size_t pdfbytes; /* current output byte */ - size_t pdflastpg; /* byte of last page mark */ - size_t pdfbody; /* start of body object */ - size_t *pdfobjs; /* table of object offsets */ - size_t pdfobjsz; /* size of pdfobjs */ -}; - struct termp_tbl { int width; /* width in fixed chars */ int decimal; /* decimal point position */ @@ -79,19 +52,20 @@ struct termp_tbl { struct termp { enum termtype type; struct rofftbl tbl; /* table configuration */ + int mdocstyle; /* imitate mdoc(7) output */ + size_t defindent; /* Default indent for text. */ size_t defrmargin; /* Right margin of the device. */ size_t rmargin; /* Current right margin. */ size_t maxrmargin; /* Max right margin. */ - size_t maxcols; /* Max size of buf. */ + int maxcols; /* Max size of buf. */ size_t offset; /* Margin offest. */ size_t tabwidth; /* Distance of tab positions. */ - size_t col; /* Bytes in buf. */ + int col; /* Bytes in buf. */ size_t viscol; /* Chars on current line. */ int overstep; /* See termp_flushln(). */ int flags; #define TERMP_SENTENCE (1 << 1) /* Space before a sentence. */ #define TERMP_NOSPACE (1 << 2) /* No space before words. */ -#define TERMP_NOLPAD (1 << 3) /* See term_flushln(). */ #define TERMP_NOBREAK (1 << 4) /* See term_flushln(). */ #define TERMP_IGNDELIM (1 << 6) /* Delims like regulars. */ #define TERMP_NONOSPACE (1 << 7) /* No space (no autounset). */ @@ -103,29 +77,27 @@ struct termp { #define TERMP_ANPREC (1 << 13) /* See termp_an_pre(). */ #define TERMP_KEEP (1 << 14) /* Keep words together. */ #define TERMP_PREKEEP (1 << 15) /* ...starting with the next one. */ - char *buf; /* Output buffer. */ + int *buf; /* Output buffer. */ enum termenc enc; /* Type of encoding. */ - void *symtab; /* Encoded-symbol table. */ + struct mchars *symtab; /* Encoded-symbol table. */ enum termfont fontl; /* Last font set. */ enum termfont fontq[10]; /* Symmetric fonts. */ int fonti; /* Index of font stack. */ term_margin headf; /* invoked to print head */ term_margin footf; /* invoked to print foot */ - void (*letter)(struct termp *, char); + void (*letter)(struct termp *, int); void (*begin)(struct termp *); void (*end)(struct termp *); void (*endline)(struct termp *); void (*advance)(struct termp *, size_t); - size_t (*width)(const struct termp *, char); + size_t (*width)(const struct termp *, int); double (*hspan)(const struct termp *, const struct roffsu *); const void *argf; /* arg for headf/footf */ - union { - struct termp_ps ps; - } engine; + struct termp_ps *ps; }; -struct termp *term_alloc(enum termenc); +void term_eqn(struct termp *, const struct eqn *); void term_tbl(struct termp *, const struct tbl_span *); void term_free(struct termp *); void term_newln(struct termp *); diff --git a/external/bsd/mdocml/dist/term_ascii.c b/external/bsd/mdocml/dist/term_ascii.c index 293f1d27d..734d0d31a 100644 --- a/external/bsd/mdocml/dist/term_ascii.c +++ b/external/bsd/mdocml/dist/term_ascii.c @@ -1,6 +1,6 @@ -/* $Vendor-Id: term_ascii.c,v 1.11 2011/01/02 12:21:07 kristaps Exp $ */ +/* $Vendor-Id: term_ascii.c,v 1.20 2011/12/04 23:10:52 schwarze Exp $ */ /* - * Copyright (c) 2010 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -21,56 +21,110 @@ #include <sys/types.h> #include <assert.h> +#ifdef USE_WCHAR +# include <locale.h> +#endif #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> +#ifdef USE_WCHAR +# include <wchar.h> +#endif #include "mandoc.h" #include "out.h" #include "term.h" #include "main.h" +/* + * Sadly, this doesn't seem to be defined on systems even when they + * support it. For the time being, remove it and let those compiling + * the software decide for themselves what to use. + */ +#if 0 +#if ! defined(__STDC_ISO_10646__) +# undef USE_WCHAR +#endif +#endif + +static struct termp *ascii_init(enum termenc, char *); static double ascii_hspan(const struct termp *, const struct roffsu *); -static size_t ascii_width(const struct termp *, char); +static size_t ascii_width(const struct termp *, int); static void ascii_advance(struct termp *, size_t); static void ascii_begin(struct termp *); static void ascii_end(struct termp *); static void ascii_endline(struct termp *); -static void ascii_letter(struct termp *, char); +static void ascii_letter(struct termp *, int); +#ifdef USE_WCHAR +static void locale_advance(struct termp *, size_t); +static void locale_endline(struct termp *); +static void locale_letter(struct termp *, int); +static size_t locale_width(const struct termp *, int); +#endif -void * -ascii_alloc(char *outopts) +static struct termp * +ascii_init(enum termenc enc, char *outopts) { - struct termp *p; - const char *toks[2]; + const char *toks[4]; char *v; + struct termp *p; - if (NULL == (p = term_alloc(TERMENC_ASCII))) - return(NULL); + p = mandoc_calloc(1, sizeof(struct termp)); + p->enc = enc; p->tabwidth = 5; p->defrmargin = 78; - p->advance = ascii_advance; p->begin = ascii_begin; p->end = ascii_end; - p->endline = ascii_endline; p->hspan = ascii_hspan; - p->letter = ascii_letter; p->type = TERMTYPE_CHAR; + + p->enc = TERMENC_ASCII; + p->advance = ascii_advance; + p->endline = ascii_endline; + p->letter = ascii_letter; p->width = ascii_width; - toks[0] = "width"; - toks[1] = NULL; +#ifdef USE_WCHAR + if (TERMENC_ASCII != enc) { + v = TERMENC_LOCALE == enc ? + setlocale(LC_ALL, "") : + setlocale(LC_CTYPE, "UTF-8"); + if (NULL != v && MB_CUR_MAX > 1) { + p->enc = enc; + p->advance = locale_advance; + p->endline = locale_endline; + p->letter = locale_letter; + p->width = locale_width; + } + } +#endif + + toks[0] = "indent"; + toks[1] = "width"; + toks[2] = "mdoc"; + toks[3] = NULL; while (outopts && *outopts) switch (getsubopt(&outopts, UNCONST(toks), &v)) { case (0): + p->defindent = (size_t)atoi(v); + break; + case (1): p->defrmargin = (size_t)atoi(v); break; + case (2): + /* + * Temporary, undocumented mode + * to imitate mdoc(7) output style. + */ + p->mdocstyle = 1; + p->defindent = 5; + break; default: break; } @@ -82,16 +136,36 @@ ascii_alloc(char *outopts) return(p); } +void * +ascii_alloc(char *outopts) +{ + + return(ascii_init(TERMENC_ASCII, outopts)); +} + +void * +utf8_alloc(char *outopts) +{ + + return(ascii_init(TERMENC_UTF8, outopts)); +} + + +void * +locale_alloc(char *outopts) +{ + + return(ascii_init(TERMENC_LOCALE, outopts)); +} /* ARGSUSED */ static size_t -ascii_width(const struct termp *p, char c) +ascii_width(const struct termp *p, int c) { return(1); } - void ascii_free(void *arg) { @@ -99,17 +173,14 @@ ascii_free(void *arg) term_free((struct termp *)arg); } - /* ARGSUSED */ static void -ascii_letter(struct termp *p, char c) +ascii_letter(struct termp *p, int c) { - /* LINTED */ putchar(c); } - static void ascii_begin(struct termp *p) { @@ -117,7 +188,6 @@ ascii_begin(struct termp *p) (*p->headf)(p, p->argf); } - static void ascii_end(struct termp *p) { @@ -125,7 +195,6 @@ ascii_end(struct termp *p) (*p->footf)(p, p->argf); } - /* ARGSUSED */ static void ascii_endline(struct termp *p) @@ -134,19 +203,16 @@ ascii_endline(struct termp *p) putchar('\n'); } - /* ARGSUSED */ static void ascii_advance(struct termp *p, size_t len) { size_t i; - /* Just print whitespace on the terminal. */ for (i = 0; i < len; i++) putchar(' '); } - /* ARGSUSED */ static double ascii_hspan(const struct termp *p, const struct roffsu *su) @@ -185,3 +251,39 @@ ascii_hspan(const struct termp *p, const struct roffsu *su) return(r); } +#ifdef USE_WCHAR +/* ARGSUSED */ +static size_t +locale_width(const struct termp *p, int c) +{ + int rc; + + return((rc = wcwidth(c)) < 0 ? 0 : rc); +} + +/* ARGSUSED */ +static void +locale_advance(struct termp *p, size_t len) +{ + size_t i; + + for (i = 0; i < len; i++) + putwchar(L' '); +} + +/* ARGSUSED */ +static void +locale_endline(struct termp *p) +{ + + putwchar(L'\n'); +} + +/* ARGSUSED */ +static void +locale_letter(struct termp *p, int c) +{ + + putwchar(c); +} +#endif diff --git a/external/bsd/mdocml/dist/term_ps.c b/external/bsd/mdocml/dist/term_ps.c index c178f90ee..82906b517 100644 --- a/external/bsd/mdocml/dist/term_ps.c +++ b/external/bsd/mdocml/dist/term_ps.c @@ -1,6 +1,6 @@ -/* $Vendor-Id: term_ps.c,v 1.45 2010/09/27 23:03:44 schwarze Exp $ */ +/* $Vendor-Id: term_ps.c,v 1.54 2011/10/16 12:20:34 schwarze Exp $ */ /* - * Copyright (c) 2010 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -34,13 +34,16 @@ #include "main.h" #include "term.h" +/* These work the buffer used by the header and footer. */ +#define PS_BUFSLOP 128 + /* Convert PostScript point "x" to an AFM unit. */ #define PNT2AFM(p, x) /* LINTED */ \ - (size_t)((double)(x) * (1000.0 / (double)(p)->engine.ps.scale)) + (size_t)((double)(x) * (1000.0 / (double)(p)->ps->scale)) /* Convert an AFM unit "x" to a PostScript points */ #define AFM2PNT(p, x) /* LINTED */ \ - ((double)(x) / (1000.0 / (double)(p)->engine.ps.scale)) + ((double)(x) / (1000.0 / (double)(p)->ps->scale)) struct glyph { unsigned short wx; /* WX in AFM */ @@ -52,6 +55,54 @@ struct font { struct glyph gly[MAXCHAR]; /* glyph metrics */ }; +struct termp_ps { + int flags; +#define PS_INLINE (1 << 0) /* we're in a word */ +#define PS_MARGINS (1 << 1) /* we're in the margins */ +#define PS_NEWPAGE (1 << 2) /* new page, no words yet */ + size_t pscol; /* visible column (AFM units) */ + size_t psrow; /* visible row (AFM units) */ + char *psmarg; /* margin buf */ + size_t psmargsz; /* margin buf size */ + size_t psmargcur; /* cur index in margin buf */ + char last; /* character buffer */ + enum termfont lastf; /* last set font */ + size_t scale; /* font scaling factor */ + size_t pages; /* number of pages shown */ + size_t lineheight; /* line height (AFM units) */ + size_t top; /* body top (AFM units) */ + size_t bottom; /* body bottom (AFM units) */ + size_t height; /* page height (AFM units */ + size_t width; /* page width (AFM units) */ + size_t left; /* body left (AFM units) */ + size_t header; /* header pos (AFM units) */ + size_t footer; /* footer pos (AFM units) */ + size_t pdfbytes; /* current output byte */ + size_t pdflastpg; /* byte of last page mark */ + size_t pdfbody; /* start of body object */ + size_t *pdfobjs; /* table of object offsets */ + size_t pdfobjsz; /* size of pdfobjs */ +}; + +static double ps_hspan(const struct termp *, + const struct roffsu *); +static size_t ps_width(const struct termp *, int); +static void ps_advance(struct termp *, size_t); +static void ps_begin(struct termp *); +static void ps_closepage(struct termp *); +static void ps_end(struct termp *); +static void ps_endline(struct termp *); +static void ps_fclose(struct termp *); +static void ps_growbuf(struct termp *, size_t); +static void ps_letter(struct termp *, int); +static void ps_pclose(struct termp *); +static void ps_pletter(struct termp *, int); +static void ps_printf(struct termp *, const char *, ...); +static void ps_putchar(struct termp *, char); +static void ps_setfont(struct termp *, enum termfont); +static struct termp *pspdf_alloc(char *); +static void pdf_obj(struct termp *, size_t); + /* * We define, for the time being, three fonts: bold, oblique/italic, and * normal (roman). The following table hard-codes the font metrics for @@ -352,49 +403,6 @@ static const struct font fonts[TERMFONT__MAX] = { } }, }; -/* These work the buffer used by the header and footer. */ -#define PS_BUFSLOP 128 - -static void -ps_growbuf(struct termp *p, size_t sz) -{ - if (p->engine.ps.psmargcur + sz <= p->engine.ps.psmargsz) - return; - - if (sz < PS_BUFSLOP) - sz = PS_BUFSLOP; - - p->engine.ps.psmargsz += sz; - - p->engine.ps.psmarg = realloc - (p->engine.ps.psmarg, - p->engine.ps.psmargsz); - - if (NULL == p->engine.ps.psmarg) { - perror(NULL); - exit((int)MANDOCLEVEL_SYSERR); - } -} - -static double ps_hspan(const struct termp *, - const struct roffsu *); -static size_t ps_width(const struct termp *, char); -static void ps_advance(struct termp *, size_t); -static void ps_begin(struct termp *); -static void ps_closepage(struct termp *); -static void ps_end(struct termp *); -static void ps_endline(struct termp *); -static void ps_fclose(struct termp *); -static void ps_letter(struct termp *, char); -static void ps_pclose(struct termp *); -static void ps_pletter(struct termp *, int); -static void ps_printf(struct termp *, const char *, ...); -static void ps_putchar(struct termp *, char); -static void ps_setfont(struct termp *, enum termfont); -static struct termp *pspdf_alloc(char *); -static void pdf_obj(struct termp *, size_t); - - void * pdf_alloc(char *outopts) { @@ -406,7 +414,6 @@ pdf_alloc(char *outopts) return(p); } - void * ps_alloc(char *outopts) { @@ -418,18 +425,19 @@ ps_alloc(char *outopts) return(p); } - static struct termp * pspdf_alloc(char *outopts) { struct termp *p; - size_t pagex, pagey, marginx, marginy, lineheight; + unsigned int pagex, pagey; + size_t marginx, marginy, lineheight; const char *toks[2]; const char *pp; char *v; - if (NULL == (p = term_alloc(TERMENC_ASCII))) - return(NULL); + p = mandoc_calloc(1, sizeof(struct termp)); + p->enc = TERMENC_ASCII; + p->ps = mandoc_calloc(1, sizeof(struct termp_ps)); p->advance = ps_advance; p->begin = ps_begin; @@ -478,17 +486,16 @@ pspdf_alloc(char *outopts) } else if (0 == strcasecmp(pp, "legal")) { pagex = 216; pagey = 356; - } else if (2 != sscanf(pp, "%zux%zu", &pagex, &pagey)) + } else if (2 != sscanf(pp, "%ux%u", &pagex, &pagey)) fprintf(stderr, "%s: Unknown paper\n", pp); - } else if (NULL == pp) - pp = "letter"; + } /* * This MUST be defined before any PNT2AFM or AFM2PNT * calculations occur. */ - p->engine.ps.scale = 11; + p->ps->scale = 11; /* Remember millimetres -> AFM units. */ @@ -504,16 +511,16 @@ pspdf_alloc(char *outopts) /* Line-height is 1.4em. */ - lineheight = PNT2AFM(p, ((double)p->engine.ps.scale * 1.4)); + lineheight = PNT2AFM(p, ((double)p->ps->scale * 1.4)); - p->engine.ps.width = pagex; - p->engine.ps.height = pagey; - p->engine.ps.header = pagey - (marginy / 2) - (lineheight / 2); - p->engine.ps.top = pagey - marginy; - p->engine.ps.footer = (marginy / 2) - (lineheight / 2); - p->engine.ps.bottom = marginy; - p->engine.ps.left = marginx; - p->engine.ps.lineheight = lineheight; + p->ps->width = (size_t)pagex; + p->ps->height = (size_t)pagey; + p->ps->header = pagey - (marginy / 2) - (lineheight / 2); + p->ps->top = pagey - marginy; + p->ps->footer = (marginy / 2) - (lineheight / 2); + p->ps->bottom = marginy; + p->ps->left = marginx; + p->ps->lineheight = lineheight; p->defrmargin = pagex - (marginx * 2); return(p); @@ -527,11 +534,12 @@ pspdf_free(void *arg) p = (struct termp *)arg; - if (p->engine.ps.psmarg) - free(p->engine.ps.psmarg); - if (p->engine.ps.pdfobjs) - free(p->engine.ps.pdfobjs); + if (p->ps->psmarg) + free(p->ps->psmarg); + if (p->ps->pdfobjs) + free(p->ps->pdfobjs); + free(p->ps); term_free(p); } @@ -550,10 +558,10 @@ ps_printf(struct termp *p, const char *fmt, ...) * into our growable margin buffer. */ - if ( ! (PS_MARGINS & p->engine.ps.flags)) { + if ( ! (PS_MARGINS & p->ps->flags)) { len = vprintf(fmt, ap); va_end(ap); - p->engine.ps.pdfbytes += /* LINTED */ + p->ps->pdfbytes += /* LINTED */ len < 0 ? 0 : (size_t)len; return; } @@ -566,12 +574,12 @@ ps_printf(struct termp *p, const char *fmt, ...) ps_growbuf(p, PS_BUFSLOP); - pos = (int)p->engine.ps.psmargcur; - len = vsnprintf(&p->engine.ps.psmarg[pos], PS_BUFSLOP, fmt, ap); + pos = (int)p->ps->psmargcur; + vsnprintf(&p->ps->psmarg[pos], PS_BUFSLOP, fmt, ap); va_end(ap); - p->engine.ps.psmargcur = strlen(p->engine.ps.psmarg); + p->ps->psmargcur = strlen(p->ps->psmarg); } @@ -582,18 +590,18 @@ ps_putchar(struct termp *p, char c) /* See ps_printf(). */ - if ( ! (PS_MARGINS & p->engine.ps.flags)) { + if ( ! (PS_MARGINS & p->ps->flags)) { /* LINTED */ putchar(c); - p->engine.ps.pdfbytes++; + p->ps->pdfbytes++; return; } ps_growbuf(p, 2); - pos = (int)p->engine.ps.psmargcur++; - p->engine.ps.psmarg[pos++] = c; - p->engine.ps.psmarg[pos] = '\0'; + pos = (int)p->ps->psmargcur++; + p->ps->psmarg[pos++] = c; + p->ps->psmarg[pos] = '\0'; } @@ -603,18 +611,18 @@ pdf_obj(struct termp *p, size_t obj) assert(obj > 0); - if ((obj - 1) >= p->engine.ps.pdfobjsz) { - p->engine.ps.pdfobjsz = obj + 128; - p->engine.ps.pdfobjs = realloc - (p->engine.ps.pdfobjs, - p->engine.ps.pdfobjsz * sizeof(size_t)); - if (NULL == p->engine.ps.pdfobjs) { + if ((obj - 1) >= p->ps->pdfobjsz) { + p->ps->pdfobjsz = obj + 128; + p->ps->pdfobjs = realloc + (p->ps->pdfobjs, + p->ps->pdfobjsz * sizeof(size_t)); + if (NULL == p->ps->pdfobjs) { perror(NULL); exit((int)MANDOCLEVEL_SYSERR); } } - p->engine.ps.pdfobjs[(int)obj - 1] = p->engine.ps.pdfbytes; + p->ps->pdfobjs[(int)obj - 1] = p->ps->pdfbytes; ps_printf(p, "%zu 0 obj\n", obj); } @@ -632,14 +640,14 @@ ps_closepage(struct termp *p) * for the page contents. */ - assert(p->engine.ps.psmarg && p->engine.ps.psmarg[0]); - ps_printf(p, "%s", p->engine.ps.psmarg); + assert(p->ps->psmarg && p->ps->psmarg[0]); + ps_printf(p, "%s", p->ps->psmarg); if (TERMTYPE_PS != p->type) { ps_printf(p, "ET\n"); - len = p->engine.ps.pdfbytes - p->engine.ps.pdflastpg; - base = p->engine.ps.pages * 4 + p->engine.ps.pdfbody; + len = p->ps->pdfbytes - p->ps->pdflastpg; + base = p->ps->pages * 4 + p->ps->pdfbody; ps_printf(p, "endstream\nendobj\n"); @@ -666,10 +674,10 @@ ps_closepage(struct termp *p) } else ps_printf(p, "showpage\n"); - p->engine.ps.pages++; - p->engine.ps.psrow = p->engine.ps.top; - assert( ! (PS_NEWPAGE & p->engine.ps.flags)); - p->engine.ps.flags |= PS_NEWPAGE; + p->ps->pages++; + p->ps->psrow = p->ps->top; + assert( ! (PS_NEWPAGE & p->ps->flags)); + p->ps->flags |= PS_NEWPAGE; } @@ -685,15 +693,15 @@ ps_end(struct termp *p) * well as just one. */ - if ( ! (PS_NEWPAGE & p->engine.ps.flags)) { - assert(0 == p->engine.ps.flags); - assert('\0' == p->engine.ps.last); + if ( ! (PS_NEWPAGE & p->ps->flags)) { + assert(0 == p->ps->flags); + assert('\0' == p->ps->last); ps_closepage(p); } if (TERMTYPE_PS == p->type) { ps_printf(p, "%%%%Trailer\n"); - ps_printf(p, "%%%%Pages: %zu\n", p->engine.ps.pages); + ps_printf(p, "%%%%Pages: %zu\n", p->ps->pages); ps_printf(p, "%%%%EOF\n"); return; } @@ -701,18 +709,18 @@ ps_end(struct termp *p) pdf_obj(p, 2); ps_printf(p, "<<\n/Type /Pages\n"); ps_printf(p, "/MediaBox [0 0 %zu %zu]\n", - (size_t)AFM2PNT(p, p->engine.ps.width), - (size_t)AFM2PNT(p, p->engine.ps.height)); + (size_t)AFM2PNT(p, p->ps->width), + (size_t)AFM2PNT(p, p->ps->height)); - ps_printf(p, "/Count %zu\n", p->engine.ps.pages); + ps_printf(p, "/Count %zu\n", p->ps->pages); ps_printf(p, "/Kids ["); - for (i = 0; i < p->engine.ps.pages; i++) + for (i = 0; i < p->ps->pages; i++) ps_printf(p, " %zu 0 R", i * 4 + - p->engine.ps.pdfbody + 3); + p->ps->pdfbody + 3); - base = (p->engine.ps.pages - 1) * 4 + - p->engine.ps.pdfbody + 4; + base = (p->ps->pages - 1) * 4 + + p->ps->pdfbody + 4; ps_printf(p, "]\n>>\nendobj\n"); pdf_obj(p, base); @@ -720,14 +728,14 @@ ps_end(struct termp *p) ps_printf(p, "/Type /Catalog\n"); ps_printf(p, "/Pages 2 0 R\n"); ps_printf(p, ">>\n"); - xref = p->engine.ps.pdfbytes; + xref = p->ps->pdfbytes; ps_printf(p, "xref\n"); ps_printf(p, "0 %zu\n", base + 1); ps_printf(p, "0000000000 65535 f \n"); for (i = 0; i < base; i++) ps_printf(p, "%.10zu 00000 n \n", - p->engine.ps.pdfobjs[(int)i]); + p->ps->pdfobjs[(int)i]); ps_printf(p, "trailer\n"); ps_printf(p, "<<\n"); @@ -752,33 +760,33 @@ ps_begin(struct termp *p) * screen yet, so we don't need to initialise the primary state. */ - if (p->engine.ps.psmarg) { - assert(p->engine.ps.psmargsz); - p->engine.ps.psmarg[0] = '\0'; + if (p->ps->psmarg) { + assert(p->ps->psmargsz); + p->ps->psmarg[0] = '\0'; } - /*p->engine.ps.pdfbytes = 0;*/ - p->engine.ps.psmargcur = 0; - p->engine.ps.flags = PS_MARGINS; - p->engine.ps.pscol = p->engine.ps.left; - p->engine.ps.psrow = p->engine.ps.header; + /*p->ps->pdfbytes = 0;*/ + p->ps->psmargcur = 0; + p->ps->flags = PS_MARGINS; + p->ps->pscol = p->ps->left; + p->ps->psrow = p->ps->header; ps_setfont(p, TERMFONT_NONE); (*p->headf)(p, p->argf); (*p->endline)(p); - p->engine.ps.pscol = p->engine.ps.left; - p->engine.ps.psrow = p->engine.ps.footer; + p->ps->pscol = p->ps->left; + p->ps->psrow = p->ps->footer; (*p->footf)(p, p->argf); (*p->endline)(p); - p->engine.ps.flags &= ~PS_MARGINS; + p->ps->flags &= ~PS_MARGINS; - assert(0 == p->engine.ps.flags); - assert(p->engine.ps.psmarg); - assert('\0' != p->engine.ps.psmarg[0]); + assert(0 == p->ps->flags); + assert(p->ps->psmarg); + assert('\0' != p->ps->psmarg[0]); /* * Print header and initialise page state. Following this, @@ -789,7 +797,6 @@ ps_begin(struct termp *p) if (TERMTYPE_PS == p->type) { ps_printf(p, "%%!PS-Adobe-3.0\n"); - ps_printf(p, "%%%%Creator: mandoc-%s\n", VERSION); ps_printf(p, "%%%%CreationDate: %s", ctime(&t)); ps_printf(p, "%%%%DocumentData: Clean7Bit\n"); ps_printf(p, "%%%%Orientation: Portrait\n"); @@ -797,8 +804,8 @@ ps_begin(struct termp *p) ps_printf(p, "%%%%PageOrder: Ascend\n"); ps_printf(p, "%%%%DocumentMedia: " "Default %zu %zu 0 () ()\n", - (size_t)AFM2PNT(p, p->engine.ps.width), - (size_t)AFM2PNT(p, p->engine.ps.height)); + (size_t)AFM2PNT(p, p->ps->width), + (size_t)AFM2PNT(p, p->ps->height)); ps_printf(p, "%%%%DocumentNeededResources: font"); for (i = 0; i < (int)TERMFONT__MAX; i++) @@ -809,7 +816,6 @@ ps_begin(struct termp *p) ps_printf(p, "%%PDF-1.1\n"); pdf_obj(p, 1); ps_printf(p, "<<\n"); - ps_printf(p, "/Creator mandoc-%s\n", VERSION); ps_printf(p, ">>\n"); ps_printf(p, "endobj\n"); @@ -824,10 +830,10 @@ ps_begin(struct termp *p) } } - p->engine.ps.pdfbody = (size_t)TERMFONT__MAX + 3; - p->engine.ps.pscol = p->engine.ps.left; - p->engine.ps.psrow = p->engine.ps.top; - p->engine.ps.flags |= PS_NEWPAGE; + p->ps->pdfbody = (size_t)TERMFONT__MAX + 3; + p->ps->pscol = p->ps->left; + p->ps->psrow = p->ps->top; + p->ps->flags |= PS_NEWPAGE; ps_setfont(p, TERMFONT_NONE); } @@ -842,25 +848,25 @@ ps_pletter(struct termp *p, int c) * in a new page and make sure the font is correctly set. */ - if (PS_NEWPAGE & p->engine.ps.flags) { + if (PS_NEWPAGE & p->ps->flags) { if (TERMTYPE_PS == p->type) { ps_printf(p, "%%%%Page: %zu %zu\n", - p->engine.ps.pages + 1, - p->engine.ps.pages + 1); + p->ps->pages + 1, + p->ps->pages + 1); ps_printf(p, "/%s %zu selectfont\n", - fonts[(int)p->engine.ps.lastf].name, - p->engine.ps.scale); + fonts[(int)p->ps->lastf].name, + p->ps->scale); } else { - pdf_obj(p, p->engine.ps.pdfbody + - p->engine.ps.pages * 4); + pdf_obj(p, p->ps->pdfbody + + p->ps->pages * 4); ps_printf(p, "<<\n"); ps_printf(p, "/Length %zu 0 R\n", - p->engine.ps.pdfbody + 1 + - p->engine.ps.pages * 4); + p->ps->pdfbody + 1 + + p->ps->pages * 4); ps_printf(p, ">>\nstream\n"); } - p->engine.ps.pdflastpg = p->engine.ps.pdfbytes; - p->engine.ps.flags &= ~PS_NEWPAGE; + p->ps->pdflastpg = p->ps->pdfbytes; + p->ps->flags &= ~PS_NEWPAGE; } /* @@ -868,22 +874,22 @@ ps_pletter(struct termp *p, int c) * now at the current cursor. */ - if ( ! (PS_INLINE & p->engine.ps.flags)) { + if ( ! (PS_INLINE & p->ps->flags)) { if (TERMTYPE_PS != p->type) { ps_printf(p, "BT\n/F%d %zu Tf\n", - (int)p->engine.ps.lastf, - p->engine.ps.scale); + (int)p->ps->lastf, + p->ps->scale); ps_printf(p, "%.3f %.3f Td\n(", - AFM2PNT(p, p->engine.ps.pscol), - AFM2PNT(p, p->engine.ps.psrow)); + AFM2PNT(p, p->ps->pscol), + AFM2PNT(p, p->ps->psrow)); } else ps_printf(p, "%.3f %.3f moveto\n(", - AFM2PNT(p, p->engine.ps.pscol), - AFM2PNT(p, p->engine.ps.psrow)); - p->engine.ps.flags |= PS_INLINE; + AFM2PNT(p, p->ps->pscol), + AFM2PNT(p, p->ps->psrow)); + p->ps->flags |= PS_INLINE; } - assert( ! (PS_NEWPAGE & p->engine.ps.flags)); + assert( ! (PS_NEWPAGE & p->ps->flags)); /* * We need to escape these characters as per the PostScript @@ -906,17 +912,17 @@ ps_pletter(struct termp *p, int c) /* Write the character and adjust where we are on the page. */ - f = (int)p->engine.ps.lastf; + f = (int)p->ps->lastf; if (c <= 32 || (c - 32 >= MAXCHAR)) { ps_putchar(p, ' '); - p->engine.ps.pscol += (size_t)fonts[f].gly[0].wx; + p->ps->pscol += (size_t)fonts[f].gly[0].wx; return; } ps_putchar(p, (char)c); c -= 32; - p->engine.ps.pscol += (size_t)fonts[f].gly[c].wx; + p->ps->pscol += (size_t)fonts[f].gly[c].wx; } @@ -930,7 +936,7 @@ ps_pclose(struct termp *p) * or anything). */ - if ( ! (PS_INLINE & p->engine.ps.flags)) + if ( ! (PS_INLINE & p->ps->flags)) return; if (TERMTYPE_PS != p->type) { @@ -938,7 +944,7 @@ ps_pclose(struct termp *p) } else ps_printf(p, ") show\n"); - p->engine.ps.flags &= ~PS_INLINE; + p->ps->flags &= ~PS_INLINE; } @@ -954,16 +960,16 @@ ps_fclose(struct termp *p) * Following this, close out any scope that's open. */ - if ('\0' != p->engine.ps.last) { - if (p->engine.ps.lastf != TERMFONT_NONE) { + if ('\0' != p->ps->last) { + if (p->ps->lastf != TERMFONT_NONE) { ps_pclose(p); ps_setfont(p, TERMFONT_NONE); } - ps_pletter(p, p->engine.ps.last); - p->engine.ps.last = '\0'; + ps_pletter(p, p->ps->last); + p->ps->last = '\0'; } - if ( ! (PS_INLINE & p->engine.ps.flags)) + if ( ! (PS_INLINE & p->ps->flags)) return; ps_pclose(p); @@ -971,9 +977,12 @@ ps_fclose(struct termp *p) static void -ps_letter(struct termp *p, char c) +ps_letter(struct termp *p, int arg) { - char cc; + char cc, c; + + /* LINTED */ + c = arg >= 128 || arg <= 0 ? '?' : arg; /* * State machine dictates whether to buffer the last character @@ -984,33 +993,33 @@ ps_letter(struct termp *p, char c) * regular character and a regular buffer character. */ - if ('\0' == p->engine.ps.last) { + if ('\0' == p->ps->last) { assert(8 != c); - p->engine.ps.last = c; + p->ps->last = c; return; - } else if (8 == p->engine.ps.last) { + } else if (8 == p->ps->last) { assert(8 != c); - p->engine.ps.last = '\0'; + p->ps->last = '\0'; } else if (8 == c) { - assert(8 != p->engine.ps.last); - if ('_' == p->engine.ps.last) { - if (p->engine.ps.lastf != TERMFONT_UNDER) { + assert(8 != p->ps->last); + if ('_' == p->ps->last) { + if (p->ps->lastf != TERMFONT_UNDER) { ps_pclose(p); ps_setfont(p, TERMFONT_UNDER); } - } else if (p->engine.ps.lastf != TERMFONT_BOLD) { + } else if (p->ps->lastf != TERMFONT_BOLD) { ps_pclose(p); ps_setfont(p, TERMFONT_BOLD); } - p->engine.ps.last = c; + p->ps->last = c; return; } else { - if (p->engine.ps.lastf != TERMFONT_NONE) { + if (p->ps->lastf != TERMFONT_NONE) { ps_pclose(p); ps_setfont(p, TERMFONT_NONE); } - cc = p->engine.ps.last; - p->engine.ps.last = c; + cc = p->ps->last; + p->ps->last = c; c = cc; } @@ -1030,7 +1039,7 @@ ps_advance(struct termp *p, size_t len) */ ps_fclose(p); - p->engine.ps.pscol += len; + p->ps->pscol += len; } @@ -1048,16 +1057,16 @@ ps_endline(struct termp *p) * lines, we'll do nasty stuff. */ - if (PS_MARGINS & p->engine.ps.flags) + if (PS_MARGINS & p->ps->flags) return; /* Left-justify. */ - p->engine.ps.pscol = p->engine.ps.left; + p->ps->pscol = p->ps->left; /* If we haven't printed anything, return. */ - if (PS_NEWPAGE & p->engine.ps.flags) + if (PS_NEWPAGE & p->ps->flags) return; /* @@ -1065,9 +1074,9 @@ ps_endline(struct termp *p) * showpage and restart our row. */ - if (p->engine.ps.psrow >= p->engine.ps.lineheight + - p->engine.ps.bottom) { - p->engine.ps.psrow -= p->engine.ps.lineheight; + if (p->ps->psrow >= p->ps->lineheight + + p->ps->bottom) { + p->ps->psrow -= p->ps->lineheight; return; } @@ -1080,37 +1089,37 @@ ps_setfont(struct termp *p, enum termfont f) { assert(f < TERMFONT__MAX); - p->engine.ps.lastf = f; + p->ps->lastf = f; /* * If we're still at the top of the page, let the font-setting * be delayed until we actually have stuff to print. */ - if (PS_NEWPAGE & p->engine.ps.flags) + if (PS_NEWPAGE & p->ps->flags) return; if (TERMTYPE_PS == p->type) ps_printf(p, "/%s %zu selectfont\n", fonts[(int)f].name, - p->engine.ps.scale); + p->ps->scale); else ps_printf(p, "/F%d %zu Tf\n", (int)f, - p->engine.ps.scale); + p->ps->scale); } /* ARGSUSED */ static size_t -ps_width(const struct termp *p, char c) +ps_width(const struct termp *p, int c) { if (c <= 32 || c - 32 >= MAXCHAR) return((size_t)fonts[(int)TERMFONT_NONE].gly[0].wx); c -= 32; - return((size_t)fonts[(int)TERMFONT_NONE].gly[(int)c].wx); + return((size_t)fonts[(int)TERMFONT_NONE].gly[c].wx); } @@ -1149,7 +1158,7 @@ ps_hspan(const struct termp *p, const struct roffsu *su) fonts[(int)TERMFONT_NONE].gly[110 - 32].wx; break; case (SCALE_VS): - r = su->scale * p->engine.ps.lineheight; + r = su->scale * p->ps->lineheight; break; default: r = su->scale; @@ -1159,3 +1168,18 @@ ps_hspan(const struct termp *p, const struct roffsu *su) return(r); } +static void +ps_growbuf(struct termp *p, size_t sz) +{ + if (p->ps->psmargcur + sz <= p->ps->psmargsz) + return; + + if (sz < PS_BUFSLOP) + sz = PS_BUFSLOP; + + p->ps->psmargsz += sz; + + p->ps->psmarg = mandoc_realloc + (p->ps->psmarg, p->ps->psmargsz); +} + diff --git a/external/bsd/mdocml/dist/test-fgetln.c b/external/bsd/mdocml/dist/test-fgetln.c new file mode 100644 index 000000000..90869cd89 --- /dev/null +++ b/external/bsd/mdocml/dist/test-fgetln.c @@ -0,0 +1,11 @@ +#include <stdio.h> +#include <stdlib.h> + +int +main(void) +{ + char *cp; + size_t sz; + cp = fgetln(stdin, &sz); + return 0; +} diff --git a/external/bsd/mdocml/dist/test-getsubopt.c b/external/bsd/mdocml/dist/test-getsubopt.c new file mode 100644 index 000000000..25e11246e --- /dev/null +++ b/external/bsd/mdocml/dist/test-getsubopt.c @@ -0,0 +1,12 @@ +#if defined(__linux__) || defined(__MINT__) +# define _GNU_SOURCE /* getsubopt() */ +#endif + +#include <stdlib.h> + +int +main(int argc, char **argv) +{ + getsubopt(argv, argv, argv); + return 0; +} diff --git a/external/bsd/mdocml/dist/test-mmap.c b/external/bsd/mdocml/dist/test-mmap.c new file mode 100644 index 000000000..db8fd8732 --- /dev/null +++ b/external/bsd/mdocml/dist/test-mmap.c @@ -0,0 +1,10 @@ +#include <sys/types.h> +#include <sys/mman.h> + +int +main(int argc, char **argv) +{ + + mmap(0, 0, PROT_READ, MAP_FILE|MAP_SHARED, -1, 0); + return 0; +} diff --git a/external/bsd/mdocml/dist/test-strptime.c b/external/bsd/mdocml/dist/test-strptime.c new file mode 100644 index 000000000..976e9c806 --- /dev/null +++ b/external/bsd/mdocml/dist/test-strptime.c @@ -0,0 +1,13 @@ +#if defined(__linux__) || defined(__MINT__) +# define _GNU_SOURCE /* strptime(), getsubopt() */ +#endif + +#include <time.h> + +int +main(int argc, char **argv) +{ + struct tm tm; + strptime(*argv, "%D", &tm); + return 0; +} diff --git a/external/bsd/mdocml/dist/tree.c b/external/bsd/mdocml/dist/tree.c index 0efbfdbb6..d65566b2f 100644 --- a/external/bsd/mdocml/dist/tree.c +++ b/external/bsd/mdocml/dist/tree.c @@ -1,6 +1,6 @@ -/* $Vendor-Id: tree.c,v 1.31 2011/01/03 13:59:21 kristaps Exp $ */ +/* $Vendor-Id: tree.c,v 1.47 2011/09/18 14:14:15 schwarze Exp $ */ /* - * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2008, 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -19,6 +19,7 @@ #endif #include <assert.h> +#include <limits.h> #include <stdio.h> #include <stdlib.h> #include <time.h> @@ -28,8 +29,9 @@ #include "man.h" #include "main.h" -static void print_mdoc(const struct mdoc_node *, int); +static void print_box(const struct eqn_box *, int); static void print_man(const struct man_node *, int); +static void print_mdoc(const struct mdoc_node *, int); static void print_span(const struct tbl_span *, int); @@ -63,6 +65,7 @@ print_mdoc(const struct mdoc_node *n, int indent) argv = NULL; argc = sz = 0; params = NULL; + t = p = NULL; switch (n->type) { case (MDOC_ROOT): @@ -90,15 +93,14 @@ print_mdoc(const struct mdoc_node *n, int indent) t = "text"; break; case (MDOC_TBL): - t = "tbl"; + /* FALLTHROUGH */ + case (MDOC_EQN): break; default: abort(); /* NOTREACHED */ } - p = NULL; - switch (n->type) { case (MDOC_TEXT): p = n->string; @@ -127,6 +129,8 @@ print_mdoc(const struct mdoc_node *n, int indent) } break; case (MDOC_TBL): + /* FALLTHROUGH */ + case (MDOC_EQN): break; case (MDOC_ROOT): p = "root"; @@ -137,8 +141,11 @@ print_mdoc(const struct mdoc_node *n, int indent) } if (n->span) { - assert(NULL == p); + assert(NULL == p && NULL == t); print_span(n->span, indent); + } else if (n->eqn) { + assert(NULL == p && NULL == t); + print_box(n->eqn->root, indent); } else { for (i = 0; i < indent; i++) putchar('\t'); @@ -158,11 +165,9 @@ print_mdoc(const struct mdoc_node *n, int indent) for (i = 0; i < (int)sz; i++) printf(" [%s]", params[i]); - printf(" %d:%d", n->line, n->pos); + printf(" %d:%d\n", n->line, n->pos); } - putchar('\n'); - if (n->child) print_mdoc(n->child, indent + 1); if (n->next) @@ -176,6 +181,8 @@ print_man(const struct man_node *n, int indent) const char *p, *t; int i; + t = p = NULL; + switch (n->type) { case (MAN_ROOT): t = "root"; @@ -195,16 +202,18 @@ print_man(const struct man_node *n, int indent) case (MAN_BODY): t = "block-body"; break; + case (MAN_TAIL): + t = "block-tail"; + break; case (MAN_TBL): - t = "tbl"; + /* FALLTHROUGH */ + case (MAN_EQN): break; default: abort(); /* NOTREACHED */ } - p = NULL; - switch (n->type) { case (MAN_TEXT): p = n->string; @@ -215,6 +224,8 @@ print_man(const struct man_node *n, int indent) /* FALLTHROUGH */ case (MAN_HEAD): /* FALLTHROUGH */ + case (MAN_TAIL): + /* FALLTHROUGH */ case (MAN_BODY): p = man_macronames[n->tok]; break; @@ -222,6 +233,8 @@ print_man(const struct man_node *n, int indent) p = "root"; break; case (MAN_TBL): + /* FALLTHROUGH */ + case (MAN_EQN): break; default: abort(); @@ -229,22 +242,65 @@ print_man(const struct man_node *n, int indent) } if (n->span) { - assert(NULL == p); + assert(NULL == p && NULL == t); print_span(n->span, indent); + } else if (n->eqn) { + assert(NULL == p && NULL == t); + print_box(n->eqn->root, indent); } else { for (i = 0; i < indent; i++) putchar('\t'); - printf("%s (%s) %d:%d", p, t, n->line, n->pos); + printf("%s (%s) %d:%d\n", p, t, n->line, n->pos); } - putchar('\n'); - if (n->child) print_man(n->child, indent + 1); if (n->next) print_man(n->next, indent); } +static void +print_box(const struct eqn_box *ep, int indent) +{ + int i; + const char *t; + + if (NULL == ep) + return; + for (i = 0; i < indent; i++) + putchar('\t'); + + t = NULL; + switch (ep->type) { + case (EQN_ROOT): + t = "eqn-root"; + break; + case (EQN_LIST): + t = "eqn-list"; + break; + case (EQN_SUBEXPR): + t = "eqn-expr"; + break; + case (EQN_TEXT): + t = "eqn-text"; + break; + case (EQN_MATRIX): + t = "eqn-matrix"; + break; + } + + assert(t); + printf("%s(%d, %d, %d, %d, %d, \"%s\", \"%s\") %s\n", + t, EQN_DEFSIZE == ep->size ? 0 : ep->size, + ep->pos, ep->font, ep->mark, ep->pile, + ep->left ? ep->left : "", + ep->right ? ep->right : "", + ep->text ? ep->text : ""); + + print_box(ep->first, indent + 1); + print_box(ep->next, indent); +} + static void print_span(const struct tbl_span *sp, int indent) { @@ -254,8 +310,6 @@ print_span(const struct tbl_span *sp, int indent) for (i = 0; i < indent; i++) putchar('\t'); - printf("tbl: "); - switch (sp->pos) { case (TBL_SPAN_HORIZ): putchar('-'); @@ -282,8 +336,14 @@ print_span(const struct tbl_span *sp, int indent) default: break; } - printf("[%s%s]", dp->string, dp->layout ? "" : "*"); - if (dp->next) - putchar(' '); + printf("[\"%s\"", dp->string ? dp->string : ""); + if (dp->spans) + printf("(%d)", dp->spans); + if (NULL == dp->layout) + putchar('*'); + putchar(']'); + putchar(' '); } + + printf("(tbl) %d:1\n", sp->line); } diff --git a/external/bsd/mdocml/dist/vol.c b/external/bsd/mdocml/dist/vol.c index bd5afd533..7e5c6b732 100644 --- a/external/bsd/mdocml/dist/vol.c +++ b/external/bsd/mdocml/dist/vol.c @@ -1,4 +1,4 @@ -/* $Vendor-Id: vol.c,v 1.8 2010/06/19 20:46:28 kristaps Exp $ */ +/* $Vendor-Id: vol.c,v 1.9 2011/03/22 14:33:05 kristaps Exp $ */ /* * Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -22,6 +22,7 @@ #include <string.h> #include <time.h> +#include "mdoc.h" #include "mandoc.h" #include "libmdoc.h" diff --git a/external/bsd/mdocml/dist/whatis.1 b/external/bsd/mdocml/dist/whatis.1 new file mode 100644 index 000000000..d3be9145c --- /dev/null +++ b/external/bsd/mdocml/dist/whatis.1 @@ -0,0 +1,172 @@ +.\" $Vendor-Id: whatis.1,v 1.7 2011/12/25 19:35:44 kristaps Exp $ +.\" +.\" Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv> +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd December 25, 2011 +.Dt WHATIS 1 +.Os +.Sh NAME +.Nm whatis +.Nd search for manual pages by page names +.Sh SYNOPSIS +.Nm +.Op Fl C Ar file +.Op Fl M Ar manpath +.Op Fl m Ar manpath +.Op Fl S Ar arch +.Op Fl s Ar section +.Ar name ... +.Sh DESCRIPTION +The +.Nm +utility searches databases generated by +.Xr mandocdb 8 +for manuals containing the word +.Ar name +in their page name, ignoring case. +It returns the header lines from all matching pages. +You can then use the +.Xr man 1 +command to get more information. +.Pp +By default, +.Nm +searches for +.Xr mandocdb 8 +databases in the default paths stipulated by +.Xr man 1 . +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl C Ar file +Specify an alternative configuration +.Ar file +in +.Xr man.conf 5 +format. +.It Fl M Ar manpath +Use the colon-separated +.Ar manpath +instead of the default list of paths searched for +.Xr mandocdb 8 +databases. +Invalid paths, or paths without manual databases, are ignored. +.It Fl m Ar manpath +Prepend the colon-separated +.Ar manpath +to the list of paths searched for +.Xr mandocdb 8 +databases. +Invalid paths, or paths without manual databases, are ignored. +.It Fl S Ar arch +Search only for a particular architecture. +.It Fl s Ar cat +Search only for a manual section. +See +.Xr man 1 +for a listing of manual sections. +.El +.Pp +Results are sorted by manual title, with output formatted as +.Pp +.D1 title(sec) \- description +.Pp +Where +.Qq title +is the manual's title (note multiple manual names may exist for one +title), +.Qq sec +is the manual section, and +.Qq description +is the manual's short description. +If an architecture is specified for the manual, it is displayed as +.Pp +.D1 title(cat/arch) \- description +.Pp +Resulting manuals may be accessed as +.Pp +.Dl $ man \-s sec title +.Pp +If an architecture is specified in the output, use +.Pp +.Dl $ man \-s sec \-S arch title +.Pp +.Nm +is identical to running +.Xr apropos 1 +as follows: +.Pp +.Dl $ apropos -- -i 'Nm~[[:<:]]term[[:>:]]' +.Sh ENVIRONMENT +.Bl -tag -width Ds +.It Ev MANPATH +Colon-separated paths modifying the default list of paths searched for +manual databases. +Invalid paths, or paths without manual databases, are ignored. +Overridden by +.Fl M . +If +.Ev MANPATH +begins with a +.Sq \&: , +it is appended to the default list; +else if it ends with +.Sq \&: , +it is prepended to the default list; else if it contains +.Sq \&:: , +the default list is inserted between the colons. +If none of these conditions are met, it overrides the default list. +.El +.Sh FILES +.Bl -tag -width "/etc/man.conf" -compact +.It Pa whatis.db +name of the +.Xr mandocdb 8 +keyword database +.It Pa whatis.index +name of the +.Xr mandocdb 8 +filename database +.It Pa /etc/man.conf +default +.Xr man 1 +configuration file +.El +.Sh EXIT STATUS +.Ex -std +.Sh SEE ALSO +.Xr apropos 1 , +.Xr man 1 , +.Xr man.conf 5 , +.Xr mandocdb 8 +.Sh HISTORY +The +.Nm +utility first appeared in +.Bx 2 . +It was rewritten from scratch as part of the +.Xr mandocdb 8 +project for +.Ox 5.1 . +.Sh AUTHORS +.An -nosplit +.An Bill Joy +wrote the original +.Bx +.Nm +in 1979. +The current version was written by +.An Kristaps Dzonsons , +.Mt kristaps@bsd.lv . diff --git a/external/bsd/mdocml/lib/Makefile b/external/bsd/mdocml/lib/Makefile index 60e75e410..9c01131a3 100644 --- a/external/bsd/mdocml/lib/Makefile +++ b/external/bsd/mdocml/lib/Makefile @@ -1,5 +1,5 @@ -# $NetBSD: Makefile,v 1.2 2010/06/01 21:32:39 joerg Exp $ +# $NetBSD: Makefile,v 1.3 2011/04/15 14:36:30 joerg Exp $ -SUBDIR= libman libmdoc libroff +SUBDIR= libmandoc .include <bsd.subdir.mk> diff --git a/external/bsd/mdocml/lib/libman/Makefile b/external/bsd/mdocml/lib/libman/Makefile deleted file mode 100644 index 326eee4d6..000000000 --- a/external/bsd/mdocml/lib/libman/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# $NetBSD: Makefile,v 1.2 2011/01/12 23:02:22 joerg Exp $ - -LIBISPRIVATE= yes - -LIB= man -SRCS= man_macro.c man.c man_hash.c man_validate.c \ - mandoc.c man_argv.c -MAN= mdoc.3 - -.include <bsd.lib.mk> diff --git a/external/bsd/mdocml/lib/libmandoc/Makefile b/external/bsd/mdocml/lib/libmandoc/Makefile new file mode 100644 index 000000000..1a18897ce --- /dev/null +++ b/external/bsd/mdocml/lib/libmandoc/Makefile @@ -0,0 +1,13 @@ +# $NetBSD: Makefile,v 1.4 2011/10/11 19:20:14 joerg Exp $ + +LIBISPRIVATE= yes + +LIB= mandoc +SRCS= man.c man_hash.c man_macro.c man_validate.c \ + arch.c att.c lib.c mdoc.c mdoc_argv.c mdoc_hash.c mdoc_macro.c \ + mdoc_man.c mdoc_validate.c msec.c st.c vol.c \ + eqn.c roff.c tbl.c tbl_data.c tbl_layout.c tbl_opts.c \ + mandoc.c read.c +MAN= mandoc.3 + +.include <bsd.lib.mk> diff --git a/external/bsd/mdocml/lib/libmdoc/Makefile b/external/bsd/mdocml/lib/libmdoc/Makefile deleted file mode 100644 index ab2cee0da..000000000 --- a/external/bsd/mdocml/lib/libmdoc/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# $NetBSD: Makefile,v 1.2 2011/01/12 23:02:22 joerg Exp $ - -LIBISPRIVATE= yes - -WARNS= - -LIB= mdoc -SRCS= mdoc_macro.c mdoc.c mdoc_hash.c mdoc_strings.c \ - mdoc_argv.c mdoc_validate.c lib.c att.c \ - arch.c vol.c msec.c st.c mandoc.c -MAN= man.3 - -.include <bsd.lib.mk> diff --git a/external/bsd/mdocml/lib/libroff/Makefile b/external/bsd/mdocml/lib/libroff/Makefile deleted file mode 100644 index efd7c5cea..000000000 --- a/external/bsd/mdocml/lib/libroff/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# $NetBSD: Makefile,v 1.2 2011/01/12 23:02:22 joerg Exp $ - -LIBISPRIVATE= yes - -LIB= roff -SRCS= roff.c tbl.c tbl_opts.c tbl_layout.c tbl_data.c -MAN= - -COPTS.tbl_layout.c= -Wno-shadow - -.include <bsd.lib.mk> diff --git a/external/bsd/mdocml/man/Makefile b/external/bsd/mdocml/man/Makefile index 24195f835..f0a167ab8 100644 --- a/external/bsd/mdocml/man/Makefile +++ b/external/bsd/mdocml/man/Makefile @@ -1,9 +1,15 @@ -# $NetBSD: Makefile,v 1.6 2011/01/12 23:02:22 joerg Exp $ +# $NetBSD: Makefile,v 1.7 2011/10/11 19:20:14 joerg Exp $ -MAN= mandoc_man.7 mandoc_char.7 mandoc_mdoc.7 mandoc_roff.7 mandoc_tbl.7 +MAN= mandoc_man.7 mandoc_char.7 mandoc_eqn.7 mandoc_mdoc.7 \ + mandoc_roff.7 mandoc_tbl.7 .include <bsd.init.mk> +mandoc_eqn.7: ${DISTDIR}/eqn.7 + ${_MKTARGET_CREATE} + rm -f ${.TARGET} + ${TOOL_CAT} ${DISTDIR}/eqn.7 > ${.TARGET} + mandoc_man.7: ${DISTDIR}/man.7 ${_MKTARGET_CREATE} rm -f ${.TARGET} @@ -24,7 +30,8 @@ mandoc_tbl.7: ${DISTDIR}/tbl.7 rm -f ${.TARGET} ${TOOL_CAT} ${DISTDIR}/tbl.7 > ${.TARGET} -CLEANFILES+= mandoc_man.7 mandoc_mdoc.7 mandoc_roff.7 mandoc_tbl.7 +CLEANFILES+= mandoc_eqn.7 mandoc_man.7 mandoc_mdoc.7 \ + mandoc_roff.7 mandoc_tbl.7 .if (${MKHTML} != "no") && (${MKMAN} != "no") FILES= ${DISTDIR}/example.style.css diff --git a/releasetools/nbsd_ports b/releasetools/nbsd_ports index 14f047d5e..bc0bca1f9 100644 --- a/releasetools/nbsd_ports +++ b/releasetools/nbsd_ports @@ -52,7 +52,7 @@ 2012/10/17 12:00:00,external/bsd/libarchive 2013/07/15 12:00:00,external/bsd/lutok 2012/10/17 12:00:00,external/bsd/Makefile -2011/01/12 23:02:22,external/bsd/mdocml +2012/10/17 12:00:00,external/bsd/mdocml 2012/10/17 12:00:00,external/gpl3/binutils 2012/10/17 12:00:00,external/gpl3/gcc 2012/10/17 12:00:00,external/gpl3/Makefile