Properly handle symlinks (hardlinks and .so only files were already ok):
Use the file name of the symlink but the inode number of the file pointed to,
such that we get multiple mlinks records but not multiple mpages records.
Also make sure they do not point outside the tree we are processing.
Issue found by kili@ in desktop-file-edit(1), thanks!
In update mode, when opening the database fails, probably because it is
missing or corrupt, just rebuild it from scratch. This also helps when
installing the very first port on a freshly installed machine
and is similar to what espie@'s classical makewhatis(8) did.
Garbage collect one pair of needless parentheses in SQL code generation;
note this doesn't affect performance, SQLite generates the same byte code.
While here, make the calls to exprspec() easier to understand.
Give the mlinks and keys tables a pageid index,
as suggested by jeremy@ and espie@.
The mlinks index speeds up basic apropos(1) searches by around 30%
because it speeds up the final SELECT FROM mlinks query by about 95%.
For large result sets, the overall speedup gets even larger, in the
extreme case of "apropos Nd~." bymore than 90%.
The keys index finally makes the apropos(1) -O option usable: It no longer
incurs relevant extra cost, while in the past it was embarrassingly slow.
This comes at a cost: Total database build times grow by about 5%,
and each index adds about 10% database size with -Q. I consider that
acceptable in view of the huge apropos(1) performance gains.
The -Q database for /usr/share/man still remains below 1 MB.
Pass the function flags SQLITE_UTF8 (because SQLITE_ANY is deprecated)
and SQLITE_DETERMINISTIC when creating deterministic functions;
best practice measure suggested by espie@ and jeremy@;
as expected by jeremy@, no measurable effect on performance.
At the end of mansearch(), fchdir() back to where we started from;
this is cleaner and helps to not scatter gmon.out files all over
the place when profiling.
Using macros in .Sh header lines, or having .Sm off or .Bk -words open
while processing .Sh, is not at all recommended, but it's not strictly
a syntax violation either, and in any case, mandoc must not die in an
assertion. I broke this in rev. 1.124.
Crash found while trying to read the (rather broken) original 4.3BSD-Reno
od(1) manual page.
Unify description handling across all document types (mdoc, man, cat).
Assert that the description is unset right before calling the parse_*
handler, and assign a default if it's still unset right afterwards.
Remove all stray asserts and default assignments found elsewhere.
This fixes SQL_STEP failures for man(7) pages lacking descriptions.
Further apropos(1) speed optimization was trickier than anticipated.
Contrary to what i initially thought, almost all time is now spent
inside sqlite3(3) routines, and i found no easy way calling less of them.
However, sqlite(3) spends substantial time in malloc(3), and even more
(twice that) in its immediate malloc wrapper, sqlite3MemMalloc(),
keeping track of all individual malloc chunk sizes. Typically about
90% of the malloced memory is used for purposes of the pagecache.
By providing an mmap(3) MAP_ANON SQLITE_CONFIG_PAGECACHE, execution
time decreases by 20-25% for simple (Nd and/or Nm) queries, 10-20% for
non-NAME queries, and even apropos(1) resident memory size as reported
by top(1) decreases by 20% for simple and by 60% for non-NAME queries.
The new function, mansearch_setup(), spends no measurable time.
The pagesize chosen is optimal:
* Substantially smaller pages yield no gain at all.
* Larger pages provide no additional benefit and just waste memory.
The chosen number of pages in the cache is a compromise:
* For simple queries, a handful of pages would suffice to get the full
speed effect, at an apropos(1) resident memory size of about 2.0 MB.
* For non-NAME queries, a large pagecache with 2k pages (2.5 MB) might
gain a few more percent in speed, but at the expense of doubling the
apropos(1) resident memory size for *all* queries.
* The chosen number of 256 pages (330 kB) allows nearly full speed gain
for all queries at the price of a 15% resident memory size increase.
Next speed optimization step for the new apropos(1).
Split manual names out of the common "keys" table into their
own "names" table. This reduces standard apropos(1) search
times (i.e. searching for names and descriptions only) by
typically about 70% for the full /usr/share/man database.
(Yes, that multiplies with the previous optimization step,
so both together have reduced search times by a factor of
more than six. I'm not done yet, expect more to come.)
Even with the minimal databases built with makewhatis(8) -Q,
this step still reduces search times by 15-20%. For both cases,
database sizes and build times hardly change (+/-2%).
After careful gprof(1)ing of the new apropos(1), move the descriptions
back from the keys table to the mpages table: I found a good way
to still use them in searches, without complication of the code.
On my notebook, this reduces typical apropos(1) search times by about 40%,
it reduces /usr/share/man database size by 6% in makewhatis(8) -Q mode
and by 2% in standard mode (less overhead storing pointers to mpages),
and it doesn't measurably change database build times (may even be
going down by a percent or so because less data is being copied
around in ohashes).
Add a new term_flushln() flag TERMP_BRIND (if break, then indent)
to control indentation of continuation lines in TERMP_NOBREAK mode.
In the past, this was always on; continue using it
for .Bl, .Nm, .Fn, .Fo, and .HP, but no longer for .IP and .TP.
I looked at this because sthen@ reported the issue in a manual
of a Perl module from ports, but it affects base, too: This patch
reduces groff-mandoc differences in base by more than 15%.
If the SYNOPSIS section contains an excessively long .Nm,
adjust the right margin to avoid running into an assertion;
output in that case now agrees with groff, too.
Fully implement the \B (validate numerical expression) and
partially implement the \w (measure text width) escape sequence
in a way that makes them usable in numerical expressions and in
conditional requests, similar to how \n (interpolate number register)
and \* (expand user-defined string) are implemented.
This lets mandoc(1) handle the baroque low-level roff code
found at the beginning of the ggrep(1) manual.
Thanks to pascal@ for the report.
We already supported (outer) user-defined strings containing references
to other (inner) user-defined strings in their values, such that the inner
ones get expanded at expansion time of the outer ones (delayed evaluation).
Now we also support specifying the name of an (outer) user-defined
string to expand using the expanded values of some other (inner)
user-defined strings (indirect reference).
Almost complete implementation of roff(7) numerical expressions.
Support all binary operators except ';' (scale conversion).
Fully support chained operations and nested parentheses.
Use this for the .nr, .if, and .ie requests.
While here, fix parsing of integer numbers in roff_getnum().
Implement the roff(7) .rr (remove register) request.
As reported by sthen@, the perl-5.18 pod2man(1) preamble
thinks cool kids use that in manuals. I hope *you* know better.
In -p (picky) mode, warn unless each filename (aka mlink)
appears as a name in the NAME section.
While here, garbage collect two unused variables, both called "match".
Warn about missing mlinks.
This is really expensive, more than tripling database build times,
so only do it when the -p (picky) option was given, but none of the
following options were given: -Q (quick), -d, -u, or -t.
Remember which names are in the NAME section.
This helps to find missing MLINKS.
Database build times do not change and database growth is minimal
(1.2% with -Q, 0.7% without -Q in /usr/share/man),
so making this optional would be pointless.
When the -n or -t flag is given to makewhatis(8),
write names and decriptions to stdout,
in a format similar to apropos(1) output.
Inspired by espie@'s makewhatis.
Instead of silently doing nothing at all,
warn and return non-zero when the manpath is empty, that is,
when /etc/man.conf is non-existent or unreadable
AND the environment variable MANPATH is unset or empty
AND no directories were given on the command line.
Inspired by the error handling in espie@'s makewhatis(8),
except that one doesn't know about MANPATH.
Rename the -W option to -p (mnemonics: picky, print to stderr):
That letter was already chosen by espie@ for OpenBSD 2.7,
so avoid being gratuitiously different more than a decade later.
Accept -v for backward compatibility with espie@'s makewhatis,
even though it does nothing right now.
The -v option of mandocdb(8) clashes with the -v option of espie@'s
makewhatis(8), which traditionally does something different,
so rename it to -D (mnemonics: Debug, Dump, Display).
Ingo Schwarze [Mon, 31 Mar 2014 01:05:32 +0000 (01:05 +0000)]
Support the CONTEXT section for kernel manual pages found in Solaris and
OpenBSD manuals. It describes which contexts you can call functions in.
from dlg@, ok jmc@ deraadt@
Ingo Schwarze [Fri, 28 Mar 2014 23:26:25 +0000 (23:26 +0000)]
Allow leading and trailing vertical lines,
and format them in the same way as groff.
While here, do not require whitespace before vertical lines
in layout specifications.
Issues found by bentley@ in mpv(1).
Ingo Schwarze [Fri, 28 Mar 2014 19:17:12 +0000 (19:17 +0000)]
Properly initialize malloc(3)ed memory.
With this bug fix, partly unitialized memory could sometimes be
returned, sometimes causing crashes by bogus free(3)s in apropos(1).
Ingo Schwarze [Wed, 26 Mar 2014 21:39:38 +0000 (21:39 +0000)]
Without bloating mandoc(1) itself, let mandocdb(8) support files
called manN/X.N.gz and catN/X.0.gz, reading them through a pipe(2)
from gunzip(1) -c. Asked for by various people in the past.
Ingo Schwarze [Wed, 26 Mar 2014 20:53:36 +0000 (20:53 +0000)]
Improve error reporting.
Simplify combining a custom format string with perror(),
avoiding many manual calls to strerror(errno).
For low-level failures, report attempted function calls.
Do not abuse the say() filename argument for files outside the basedir,
and even less for other text.
Ingo Schwarze [Sun, 23 Mar 2014 15:14:50 +0000 (15:14 +0000)]
Retire the old concat() function.
For .Sh, i wasn't even needed at all.
For .Dd, .Nm, and .Os, use the new mdoc_deroff() instead.
This gets rid of the last limited-size static buffers in this file,
hence eliminates the last explicit MANDOCERR_MEM throwers here,
and it shortens the code by 50 lines.
Ingo Schwarze [Sun, 23 Mar 2014 12:26:58 +0000 (12:26 +0000)]
If a man(7) NAME section contains macros, avoid truncated or empty
entries for .Nd in mandocdb(8), instead use the macro content
recursively. This improves indexing of more than 200 manuals
in Xenocara, i.e. more than 15%, in particular GL and some Xkb.
Ingo Schwarze [Sun, 23 Mar 2014 11:59:17 +0000 (11:59 +0000)]
The files mandoc.c and mandoc.h contained both specialised low-level
functions used for multiple languages (mdoc, man, roff), for example
mandoc_escape(), mandoc_getarg(), mandoc_eos(), and generic auxiliary
functions. Split the auxiliaries out into their own file and header.
Ingo Schwarze [Sun, 23 Mar 2014 11:25:25 +0000 (11:25 +0000)]
The files mandoc.c and mandoc.h contained both specialised low-level
functions used for multiple languages (mdoc, man, roff), for example
mandoc_escape(), mandoc_getarg(), mandoc_eos(), and generic auxiliary
functions. Split the auxiliaries out into their own file and header.
While here, do some #include cleanup.
Ingo Schwarze [Thu, 20 Mar 2014 02:57:28 +0000 (02:57 +0000)]
Remove currently unimplemented macros from the lists of used-defined
macros to be cleared during .Dd and .TH because clearing them at that
point defeats the purpose of backup implementations provided in the
manual page itself, some of which _do_ work with mandoc(1).
While here, add the new .%C macro to the list to be cleared.
Ingo Schwarze [Wed, 19 Mar 2014 22:33:09 +0000 (22:33 +0000)]
Register pure .so pages as mlinks, not as mpages.
This doesn't affect /usr/share/man, but improves /usr/X11R6/man:
* Eliminates multiple apropos(1) output for such pages.
* Reduces X11R6 database size from 450 kB to 240 kB (-47%).
* Reduces X11R6 database build time from 1.68s to 1.00s (-40%).
Ingo Schwarze [Wed, 19 Mar 2014 22:20:43 +0000 (22:20 +0000)]
Without the MPARSE_SO option, if the file contains nothing but a
single .so request, do not read the file pointed to, but instead
let mparse_result() provide the file name pointed to as a return
value. To be used by makewhatis(8) in the future.
Ingo Schwarze [Wed, 19 Mar 2014 21:51:20 +0000 (21:51 +0000)]
Generalize the mparse_alloc() and roff_alloc() functions by giving
them an "options" argument, replacing the existing "inttype" and
"quick" arguments, preparing for a future MPARSE_SO option.
Store this argument in struct mparse and struct roff, replacing the
existing "inttype", "parsetype", and "quick" members.
No functional change except one tiny cosmetic fix in roff_TH().
Ingo Schwarze [Tue, 18 Mar 2014 16:56:10 +0000 (16:56 +0000)]
Allow checking that databases are up to date even when you have no write
permission on the databases, as requested by espie@ quite some time ago.
But make sure to not slow database generation down when you do have write
permission, and to not delay error reporting in -Q mode.
Ingo Schwarze [Mon, 17 Mar 2014 09:43:56 +0000 (09:43 +0000)]
Sync to OpenBSD:
* do not talk about shell globbing
* describe logical operations
* improve examples
* add HISTORY
* some wording improvements for clarity
Ingo Schwarze [Thu, 13 Mar 2014 19:23:50 +0000 (19:23 +0000)]
In -Tutf8 mode, make sure that hyphens get counted against the output line
length even when they are breakable. Before this, a line containing N
breakable hyphens could get up to N characters wider than the right margin
in -Tutf8 output mode.
Issue reported by tedu@ on <bugs at OpenBSD>.
Ingo Schwarze [Sat, 8 Mar 2014 16:22:04 +0000 (16:22 +0000)]
In .nf mode, use the MAN_LINE flag to detect input line breaks
instead of the man_node line member. This is required to preserve
line breaks contained in user-defined macros called in .nf mode.
Found in a code audit triggered by fixing a similar issue in .TP.
Ingo Schwarze [Sat, 8 Mar 2014 15:50:41 +0000 (15:50 +0000)]
To find out whether .TP head arguments are same-line or next-line arguments,
use the MAN_LINE flag instead of the man_node line member.
This is required such that user-defined macros wrapping .TP work correctly.
Issue found by Havard Eidnes in Tcl_NewStringObj(3), reported via
the NetBSD bug tracking system and Thomas Klausner <wiz at NetBSD>.
Ingo Schwarze [Sat, 8 Mar 2014 04:43:54 +0000 (04:43 +0000)]
Improve .if/.ie condition handling.
* Support string comparisons.
* Support negation not only for numerical, but for all conditions.
* Switch the `o' condition from false to true.
* Handle the `c', `d', and `r' conditions as false for now.
* Use int for boolean data instead of rolling our own "enum roffrule";
needed such that we can use the standard ! and == operators.
Havard Eidnes reported via the NetBSD bug tracking system that some
Tcl*(3) manuals need this, and Thomas Klausner <wiz at NetBSD>
forwarded the report to me. This doesn't make the crazy Tcl*(3)
macrology maze happy yet, but brings us a bit closer.
Ingo Schwarze [Fri, 7 Mar 2014 18:37:37 +0000 (18:37 +0000)]
In roff_cond_sub(), make sure that the incorrect input sequence `\\}',
when found on a macro line, does not close a conditional block.
The companion function roff_cond_text() already did this correctly,
but make the code more readable without functional change.
While here, report the correct column number in related error messages.
Ingo Schwarze [Fri, 7 Mar 2014 02:22:05 +0000 (02:22 +0000)]
Three bugfixes related to the closing of conditional blocks:
1. Handle more than one `\}' on macro lines, as it was already done
for text lines.
2. Do not treat `\}' as a macro invocation after a dot at the beginning
of a line. That allows more than one `\}' to work on lines starting
with `.\}'. It also simplifies the code.
3. Do not complain about characters following `\}'. Those are not lost,
but handled normally both on text and macro lines.
Ingo Schwarze [Wed, 5 Mar 2014 23:14:46 +0000 (23:14 +0000)]
In -Tutf8 mode, mandoc_char(7) named accent character escape sequences
have to render as non-combining accents; if you want combining accents,
you have to explicitly specify them using the Unicode character numbers
for combining accents, or you can use character escape sequences for
accented characters. This lets mandoc behave like groff.
Additionally, both the Ossanna/Kernighan/Ritter troff manual and
the GNU troff manual say that \' and \` are equivalent to \(aa and
\(ga, respectively, so do the same for these. This mitigates issues
with man(7) code autogenerated by texinfo2man(1), which mistranslates
TeX ` and ' to \` and \' instead of \(oq and \(cq as reported by
sthen@ and as analyzed by bentley@.
Ingo Schwarze [Mon, 3 Mar 2014 18:53:27 +0000 (18:53 +0000)]
- remove index.html, it is now part of the website repo
- install mandocdb, manpage, and apropos
- and some general cleanup (e.g., installcgi is .PHONY)
Ingo Schwarze [Mon, 3 Mar 2014 17:08:26 +0000 (17:08 +0000)]
Move the regression suite to the attic.
It has not been used or maintained for several years,
and we won't start using it now.
Devlopment regression testing is done in OpenBSD, and
there is no value in maintaining two regression suites in parallel.
Ingo Schwarze [Sun, 16 Feb 2014 14:26:55 +0000 (14:26 +0000)]
After Werner Lemberg accepted and committed some updates to the manual
page template contained in groff_mdoc(7), catch up with our own stuff.
In particular, allow ERRORS in section 4 and DIAGNOSTICS in section 9.
ok jmc@
Ingo Schwarze [Fri, 14 Feb 2014 23:24:26 +0000 (23:24 +0000)]
Parse and ignore the roff(7) .ce request (center some lines).
We even parse and ignore the .ad request (adjustment mode),
and it doesn't make sense to more prominently warn about
temporary than about permanent adjustment changes.
Request found by naddy@ in xloadimage(1) and by juanfra@ in racket(1).
Ingo Schwarze [Fri, 14 Feb 2014 23:05:20 +0000 (23:05 +0000)]
Implement the roff(7) .as request (append to user-defined string).
Missing feature found by jca@ in ratpoison(1).
The ratpoison(1) manual still doesn't work because it uses .shift
and .while, too (apparently, ratpoison is so complex that it
needs a Turing-complete language to even format its manual :-).
Ingo Schwarze [Fri, 14 Feb 2014 22:27:41 +0000 (22:27 +0000)]
Handle some predefined read-only number registers, e.g. .H and .V.
In particular, this improves handling of the pod2man(1) preamble;
for examples of the effect, see some author names in perlthrtut(1).
Missing feature reported by Andreas Voegele <mail at andreasvoegele dot com>
more than two years ago. Written at Christchurch International Airport.
Ingo Schwarze [Fri, 24 Jan 2014 22:54:33 +0000 (22:54 +0000)]
Supplement the documentation of the .St macro by minimal commentary
regarding the content and relationships of the various standards,
and sort and group them.
tweaks and ok guenther@, ok millert@ sobrado@ jmc@
Ingo Schwarze [Sun, 19 Jan 2014 00:09:38 +0000 (00:09 +0000)]
Support a second -v on mandocdb(8) to show keys while they are being added;
i need that for debugging, in particular to be used with -t.
To be able to do so, provide a global table of key names, for reuse.
Ingo Schwarze [Sat, 18 Jan 2014 08:23:55 +0000 (08:23 +0000)]
Sort the macro keys by their real-world frequency to reduce the average
mask size. No functional change.
This shrinks the standard /usr/share/man database by 7%, now at 10.3x
the size of whatis.db, and with -Q even by 11%, now at 3.0x of whatis.db.
Now i'm out of ideas to easily shrink the size of the database.
Ingo Schwarze [Sat, 18 Jan 2014 08:21:03 +0000 (08:21 +0000)]
Drop the AUTOINCREMENT PRIMARY KEYs from the mlinks and keys tables.
They are completely unused, and i cannot imagine what they *could*
ever be used for; but apparently, they are expensive to generate.
Standard DB build time goes down by 10%, now at 1.9x of makewhatis.
Standard DB size goes down by 4%, now at 11x of makewhatis.
DB build time with -Q goes down by 15%, now at 0.28x of makewhatis.
DB size with -Q goes down by 3%, now at 3.35x of makewhatis.
Ingo Schwarze [Sat, 18 Jan 2014 08:19:18 +0000 (08:19 +0000)]
Despite some experimenting, i'm unable to find any relevant effect of
creating an index for the keys table on apropos(1) search times;
apparently, adding that index was premature optimization in the first
place; so, stop adding that index.
Its root gone, the following evil is reduced (/usr/share/man on my notebook)
- DB build time with -Q goes down by 15%, now at 1/3 of makewhatis
- DB size with -Q goes down by 35%, now at 3.5x of makewhatis
- full DB build time goes down by 12%, now at 2.1x of makewhatis
- full DB size goes down by 42%, now at 11.5x of makewhatis
Ingo Schwarze [Tue, 7 Jan 2014 09:10:45 +0000 (09:10 +0000)]
Cache the result of uname(3) such that we don't need to call it
over and over again for each manual; found with gprof(1).
Speeds up mandocdb(8) -Q by 3%, now at 39.5% of makewhatis(8).
Ingo Schwarze [Mon, 6 Jan 2014 23:46:07 +0000 (23:46 +0000)]
Gprof(1) is fun. You should use it more often.
Another 10% speedup for mandocdb(8) -Q, and even 3% without -Q.
With -Q, we are now at 41% of the time required by makewhatis(8).
Do not copy predefined strings into the dynamic string table, just
leave them in their own static table and use that one as a fallback
at lookup time. This saves us copying and deleting them for each manual.
No functional change.
Ingo Schwarze [Mon, 6 Jan 2014 22:39:25 +0000 (22:39 +0000)]
Another 18% speedup for mandocdb(8) -Q, found by gprof(1).
In -Q mode, refrain form validating and normalizing the format
of the date given in .Dd or .TH, as it won't be used anyway.
For /usr/share/man, mandocdb -Q now takes 45% of the time of makewhatis(8).