Apropos Replacement : Development of a full text search tool for man pages
Abhinav Upadhyay<er.abhinav.upadhyay@gmail.com>

Abstract
Manual pages are a key component of Unix like operating systems, they have played a significant role in the
success of Unix over the years. Man pages are the mostauthentic source of reference for a system administrator
or a programmer. However, there has been a lack ofgood search tool to make man pages more accessible.
Traditionally, apropos(1) has been there as a searchinterface but it was developed in the early days of Unix
when computing resources were scarce and that is theprimary reason for its simple design and limited searchcapabilities.
This paper discusses a new implementation of apropos done by Abhinav Upadhyay and mentored by Jörg
Sonnenberger as part of Google Summer of Code 2011,
for The NetBSD Foundation. The goal of this project
was to replace the conventional apropos in NetBSD witha modern version which supports full text searches.

results or possibly a dead end. In the modern computing
world, where hard problems like searching the World
Wide Web have been solved [3] to a sufficient degree,
it makes perfect sense to leverage the advancement intechnology in order to come up with a better search tool
for man pages.
In present times, the machines are powerful andcapable of running the search algorithms efficiently.
Disk space is also sufficiently cheap that any extra
space incurred by indexing of additional metadata fromman pages can be easily afforded. These are necessary
prerequisites for building an effective search tool.
In this paper, the limitations of the traditional implementation of apropos are discussed along with brief
details of how these were overcome as part of thisproject. Additionally, a comparison of other modern
implementations of apropos has been done.

2
1

Introduction

Jörg Sonnenberger<joerg@NetBSD.org>

2.1

Limitations of Conventional apropos
Lack of support for free form queries

The classical version of apropos has been implemented
by simply indexing the keywords in the NAME sectionof the man pages in a plain text file (whatis.db) [2] andperforming searches on it. The reason for this simple
design was most probably lack of computing resourcesin the early days. The plain text file consisting of
keywords hardly takes few hundreds of kilo bytes of
disk space and performing search on a plain text file isquite easy.

As noted earlier the conventional apropos is limited to
the keywords used in the NAME section of the man
pages. This means that the users do not have a whole
lot of options for specifying keywords in their queries.
Besides this, they cannot search for keywords which
are not usually specified in the title of a man page, forexample a query like EINVAL would return no results.
See listing 1 for concrete examples.

This simplified design of apropos resulted in limited
utility and usability. Only if the users know the exact
keywords do they get the appropriate results; otherwise
most of the times the searches are full of irrelevant

2.2

Lack of basic language support

Another major limitation of the classical version of
apropos is that it is not smart enough to provide support

for basic natural language processing constructs, likestemming or spelling corrections. As it can be seen inlisting 2, while apropos returns the correct result for
the query “make directories”, it fails when the keyword“directory” is used in place of “directories”, eventhough the two words are based on same root word.

index can be combined with a ranking algorithm which
exploits the structured nature of the data to give more
relevant results to the user, and to build a high quality
search interface for manual pages. Such a search tool
will solve many of the problems associated with theconventional apropos(1) as noted before and discussed
as follows:

Similarly, it is very common for users to misspell keywords in a query and apropos has no support for detecting it and offering any useful behavior either (see listing
3).

2.3

Free Form Queries
The users can express their queries in more natural
language form as the searches are no longer limited
to the the NAME section. For example, queries like“installing new software package” may now produce relevant results.

Unintelligible Output

Because of the way apropos works, sometimes its output
can be unintelligible and it can be very hard for the user
to identify relevant results, see listing 4 for an example.

2.4

Basic Natural Language Processing Support
When parsing the man pages and building theindex, tokens are preprocessed after extraction fromthe man pages to support some of the very basic
natural language processing functionalities. In this
implementation, the Porter stemming algorithm[5] has been used to reduce the individual tokens
extracted from the man pages to their root words.
This enables support for more flexible searches.
For example both “Installing new packages” and“install new package” will return same results.

Other Problems

Apart from the search related problems there are a few
issues related to the way man pages are handled in
NetBSD. The different aliases of the man pages are
stored on the file system in the from of hard (or symbolic)links and these have to be specified in the makefiles explicitly using the MLINKS mechanism. This approachworks fine but it is a mess from maintenance point ofview. It should be possible to fix this by utilizing theindex already built and maintained by apropos, but yet
again, the simplistic implementation of apropos does notleave any room for improvement.

3

Similarly along with the inverted index, a dictionary of the keywords frequently occurring in the
corpus of man pages is also built and used to support spelling suggestion.
Bookkeeping of man page metadata
In this implementation, additional metadata related
to the man pages, for example an MD5 hash, thedevice id, inode number and modification time of
the man page files are kept in the database. This
allows fast incremental update of the index as new
man pages are installed or the old ones are updated.

Solution: A new apropos

This project proposes a very simple and straightforward
solution to solve these problems and make man pages
more usable. The idea is to exploit the inherent semantics and structure of the man pages. The mdoc(7) [21]and man(7) [16] macros used for writing man pages aresemantically quite rich, those macros combined with thecontext of the surrounding section of the man page inwhich they have been used, can act as an indicator of therelevancy of the content. For example, the .Nm macro
when used inside of the NAME section holds moresignificance than if it is used elsewhere. Similarly thedescription of various errno values in the intro(2) man
page has more important information than the mentionof those errno values in the RETURN VALUES sectionof various man pages from section 3.

Similarly a separate index of all the man pagealiases is stored and maintained. This provides anoption to get rid of all the hard or symbolic links ofthe man pages scattered throughout the filesystem,
and also for clean up of the MLINKS mess in themakefiles.

3.1

Tools Used

The two main operations that are critical for this project
are parsing of the man pages and building of an index
of the data obtained from the parsing process. These arehighly specific problems, and solving them from scratch

In essence, it should be possible to parse and extract
the structurally meaningful data out of man pages andindex them in the form of an inverted index [4]. The2

$ apropos “add new user”
add new user: nothing appropriate$ apropos “get process status”
get process status: nothing appropriate$ apropos “termcap database”
termcap database: nothing appropriate

Listing 1: No results for free form queries$ apropos “make directories”
mkdir (1) - make directories$ apropos ”make directory”
make directory: nothing appropriate$ apropos “upgrading package”
pkg_add (1) - a utility for installing and upgrading software package distributions$ apropos “upgrading packages”
upgrading packages: nothing appropriate

Listing 2: No support for stems or words with same root

$ apropos “copy strings”
stpcpy, stpncpy, strcpy, strncpy (3) - copy strings$ apropos “coppy strings”
coppy strings: nothing appropriate

Listing 3: No spelling correction$ apropos power
PCI, pci_activate, pci_bus_devorder, pci_chipset_tag_create,
pci_chipset_tag_destroy, pci_conf_read, pci_conf_write,
pci_conf_print, pci_conf_capture, pci_conf_restore, pci_find_device,
pci_get_capability, pci_mapreg_type, pci_mapreg_map, pci_mapreg_info,
pci_intr_map, pci_intr_string, pci_intr_evcnt, pci_intr_establish,
pci_intr_disestablish, pci_get_powerstate, pci_set_powerstate,
pci_vpd_read, pci_vpd_write, pci_make_tag, pci_decompose_tag,
pci_findvendor, pci_devinfo, PCI_VENDOR, PCI_PRODUCT, PCI_REVISION (9)- Peripheral Component Interconnect
PMF, pmf_device_register, pmf_device_register1, pmf_device_deregister,
pmf_device_suspend, pmf_device_resume, pmf_device_recursive_suspend,
pmf_device_recursive_resume, pmf_device_resume_subtree,
pmf_class_network_register, pmf_class_input_register,
pmf_event_inject, pmf_set_platform, pmf_get_platform (9) - power
management and inter-driver messaging framework
acpi (4) - Advanced Configuration and Power Interface
acpipmtr (4) - ACPI Power Meter
amdpm (4) - AMD768 Power Management Controller and AMD8111 System
Management Controller
...
.
.
.

Listing 4: Unintelligible output of apropos(1)3would be a separate project in its own right, therefore thisproject tried to avoid reinventing the wheel and used existing tools and libraries which are battle tested and very
successful. libmandoc [6] from the mdocml [18] project
has been used for parsing the man pages and sqlite [7] forindexing and storing the parsed data on the file system.

(changed mtime).
In the second pass makemandb generates MD5checksum of the files obtained from the previous
stage and for each of these checksums, it checks inthe db, whether this MD5 checksum already exists
in the db or not. If the MD5 checksum is alreadypresent in the database, then this was just a false
alarm and makemandb does not need to parse thefile, it simply updates the metadata of that file in the
database. In case the MD5 checksum of a file does
not already exist in the database, then that means thefile is either a newly installed man page or an older
copy of a man page was updated, makemandb feeds
such man pages to the parser and extracts interesting data out of them, later on storing the data in the
FTS table in the database.

libmandoc
libmandoc is a library interface to a validating compiler for man pages. It provides interface to parseand build an AST (Abstract Syntax Tree) of the man
page. It also provides an interface for traversing thattree in order to extract the data from its nodes.
sqlitesqlite is an embedded relational database management system providing a relatively small and easy
to use C library interface. One of the main reasonsfor choosing it over the myriad of other possible
options is that it provides built in support for fulltext search through its FTS virtual table module [8].
The FTS module can be accessed using pretty muchstandard SQL syntax, and it is still flexible enoughto accept user supplied ranking function to suit theneeds of the application. Besides that, another advantage of sqlite is that, being an RDBMS, it makes
it very easy to store additional metadata in the formof normal database tables without any hassles.

4
4.1

Database Schema
During the initial stage of the project, the structureof the database was kept simple. The FTS tableconsisted of 3 columns: name, name desc, anddesc. The name and name desc columns
stored the name of the man page and the one line
description from the NAME section respectively,
while the desc column stored the content fromthe rest of the sections. This approach worked quite
well for a small set of man pages (for example
the 4000 or so man pages in the base set of
NetBSD). However, as the number of documents
were increased (for example including man pages
from pkgsrc), the quality of search started deteriorating. This was mainly because bulk of the parsed
data was being stored in the same column in the
database and the ranking algorithm had no wayof identifying more relevant results except fromidentifying whether the match was found in the
NAME section or any other section.

Implementation Details
makemandb

makemandb(8) [9] is the key component of this implementation. It is a command line tool which traverses thefilesystem, reads the raw man page source files, extracts
the interesting data from them using the libmandoc
parser and then stores that data in an FTS table using
sqlite.

To rectify this, first there was an attempt to try
out better ranking schemes (the various ranking
schemes that were tried out during the development of the project are discussed later). Better ranking schemes required storing precomputed
term weights [19] on the file system, this almost
doubled the storage requirements, therefore suchranking schemes were discarded later on, and the
database schema was decomposed further into morecolumns. The decomposition into more columns
was done to represent the most commonly occurring sections in usual Unix man pages, for example NAME, DESCRIPTION, LIBRARY, RETURNVALUES, EXIT STATUS, ERRORS etc. Such a
decomposition allowed for an elaborate ranking

Operation of makemandb
makemandb uses a two pass algorithm to index
the man pages. In the first pass it obtains thelist of directories containing man page files fromman.conf and starts traversing those directories.
It obtains the {dev t, ino t, mtime} of all the files
using stat(2). A similar set of metadata is stored
in the database (referring to the last successfulindexing operation), makemandb takes a difference(the set difference operation) of the two sets ofmetadata to obtain the list of man page files on thefile system which are either newly installed (new{dev t, ino t} pairs) or they have been updated
4

The Database has three tables:
1. mandb
2. mandb_meta
3. mandb_links(1) mandb:
The main FTS table which contains all the content parsed from man pages
COLUMN NAME
1. section
2. name
3. name_desc
4. desc
5. lib
6. return_vals
7. env
8. files9. exit_status
10. diagnostics
11. errors
12. md5_hash

DESCRIPTION
Section number
The name of the man page
Short description from NAME section
Contains the content from DESCRIPTION section and any othersection which is not stored in a separate column.
The LIBRARY section
RETURN VALUES section
ENVIRONMENT section
FILES section
EXIT STATUS section
DIAGNOSTICS section
ERRORS section
An MD5 hash of the contents of the man page (UNIQUE).

(2) mandb_meta:
This table maintains essential metadata of all the indexed man page files.
COLUMN NAME
1. device
2. inode
3. mtime
4. file5. md5_hash
6. id

DESCRIPTION(dev_t)Logical device number from stat(2)(ino_t)Inode number from stat(2)Last modification time from stat(2)Absolute path name (UNIQUE constraint)
MD5 Hash of the man page file (UNIQUE)
A unique integer ID referring to a page in mandb (PRIMARY KEY)

(3) mandb_links:
This is an index of all the hard/soft links of the man pages. The list of
the aliases is usually obtained from the multiple .Nm entries in the NAME
section of a man page.
COLUMN NAME
1. link
2. target
3. section
4. machine

DESCRIPTION
The name of the hard/soft link (UNIQUE index)
Name of the target page to which the link points
The section number
The machine architecture (if any) for which the page isrelevant.

Listing 5: Database Schema

5scheme, which could assign different weights toeach of these columns, based on their relevancy.
The final schema of the database is shown in listing 5

4.2

project took several stabs at coming up with a suitableranking algorithm for apropos.
1.
Initially the database schema was quite simple, it consisted of only three columns name,name desc, desc (as described previously).
At this point, there weren’t too many documents inthe corpus, therefore nothing sophisticated was required. The basic intuition was that, a match foundin the NAME section of a man page has more weight
as compared to a match found in any other section.
This ranking scheme worked well for a small set ofman pages in the corpus.

apropos

apropos was written from scratch to use the FTS index
created by makemandb. Since, unlike the traditional
apropos, this version of apropos is not limited tosearching within only the NAME section, the resulting
number of search results is usually quite high, therefore
new apropos employs a sophisticated ranking algorithm
to filter out the most relevant results and rank themup. To avoid cluttering the output and make the userinterface clean, the new apropos displays only the top
10 results by default with options to display more results
if required. During the development and testing of the
project it has been observed that, for a query, most often
than not the top 10 results are sufficient.

2.
As more and more man pages were being added
to the corpus for testing purposes, the quality ofsearch results started to dilute. At this point oftime, a completely new approach was adopted for
ranking the results. In the information retrieval
literature, tf-idf [19] weights based ranking models
are very common. The tf in tf-idf stands for Term
Frequency and idf stands for Inverse Document
Frequency.

Another key aspect of any search application is tofilter out or avoid stop-words . Words like “the”, “a”,
“an”, “this” etc. come under the category of stopwords, these are the words which are very commonlyused in the language. Stop-words usually skew the
search results because of their sheer frequency in the
corpus. The usual practice in the information retrieval
world is to filter such stop-words while building theindex, however, in case of this project, it proved to be
non-trivial within the given time constraints. Therefore
it was decided that, rather than eliminating stop-words
from the index, a reasonable trade off can be made byfiltering out any stop-words from the user’s search queryand querying the database for only the keywords which
do not come under the category of stop-words.

4.3

Term Frequency: The term frequency of a term t
in a document d refers to the count of the numberof times the term t appears in the document d
Inverse Document Frequency: The idf of a termt is the number of documents in which the term

appears at least once.
Term frequency is a local factor, it is concerned
only with the number of occurrences of the searchterms in one particular document at a time. While
inverse document frequency is a global factor, inthe sense that it indicates the discriminating powerof a term. If a term appears in only a selected setof documents, then that term separates those setof documents from the rest. Therefore, ranking
obtained by combining these two factors brings up
more relevant documents.

apropos-utils

apropos-utils [10] is a small library interface provided
with this implementation. It provides functions forquerying the FTS index and for processing the results ina user supplied callback function. Its main purpose is todevelop different interfaces on top of it for different use
cases. For instance a CGI front end has been built using
it for doing the searches from a web browser, similarly
an IRC bot was also developed utilizing this interface.

The weight of a term t in document d is calculatedby the following formula:weight = t f × id f

4.4

Ranking Algorithm

Where tf = Term frequency of term t in document d

The ranking algorithm is the most interesting and most
crucial component of any search application, it is the deciding factor of the usefulness of the application. This

Inverse document frequency is calculated using thefollowing formula:6

columns representing some of the most common
sections found in man pages (see Listing 5)
and a fast yet sophisticated ranking algorithm wasadopted, to exploit this structured nature of the data.

id f = log( NNt )Where N = Total number of documents in the
corpusNt = Number of documents in which term t occurs(at least once).
So for a term which appears in only one document, it will have id f = log(n), while a term
which appears in all the documents, it will haveid f = log(1) = 0. For example a term like “the”
will have a high term frequency in almost all the
documents, but at the same time it will have its inverse document frequency almost close to 0, which
will nullify its effect on the quality of search results.

Okapi BM25F [15] is considered one of the mostsuccessful probabilistic models for information
retrieval. It is based on tf-idf scheme but it takes
into account for the structure of the data. It allows
for separate weights to be assigned for different
parts of a structured document to come up with
better relevance rankings. The exact implementation of this algorithm did not really provide any
great results and therefore it had to be adapted andmodified to suit the needs of apropos, considering
the structure of the database schema. The actual
algorithm implemented is described in pseudo-code
below. apropos executes this function for each of
the document obtained as part of the result set for
the query and computes their relevancy weight.
The documents are ranked in decreasing order of
their weights.

A lot of research has been done on tf-idf weights
based ranking algorithms and various techniques
have been proposed over the years. According toa survey done by Salton and Buckley in 1988 [20],the following ranking scheme was found to be mosteffective:t f ·log( NN )tq

∑ (t f ·log( NNt ))2

The implementation of the above scheme proved tobe very slow. It required too many computations
and these were required to be done for each search
result separately to compute its relevance weight. Ina state of the art search application, the index would
usually store precomputed tf-idf weights on the filesystem, in which case the overhead of computing
weights of each individual search result would require very less work, leading to better performance.
An attempt was made to compute the tf-idf weights
while indexing the man pages and store them in a
separate table. This lead to high quality search results but it also brought up a serious issue. Storing
precomputed weights on the file system, more thandoubled the storage requirements of the database index. As a concrete example, it took close to 90 MB
to index about 8000 documents. Without the precomputed weights, the database size requirement
was close to 45 MB for the same number of pages.

nhitcount =Number of occurrences ofphrase p in column c in
current document

nglobalhitcount = Number of occurrences ofphrase p in column c inall the documents.
ndocshitcount = Number of documents inwhich phrase p occurs
in column c, at least
once.

Listing 6: Definition of important entities used inalgorithm 1

3.
Since the conventional apropos required only a
few hundred kilobytes of disk space, the disk
space requirements of new apropos seemed hyperbolic, therefore it was decided later on to look
for alternative ranking schemes. At this point the
database schema was decomposed into several
7

Algorithm 1 Compute Relevance Weight of a Document
for a Given User Query
Require: User query q
Require: Document d whose weight needs to be computed
Require: An array weights consisting of preassigned
weights for different columns of the FTS table
1: tf ← 0.0
2: idf ← 0.0
3: k ← 3.5. k is an experimentally determinedparameter
4: doclen ← length of the current document
5: ndoc ← Total number of documents in the corpus
6: for each phrase p in q do
7:
for each column c in the FTS table do8:w ← weights[c]. weight for column c
ndoc
)×w
9:
id f ← id f + log( ndocshitcountDB database but still its index is limited to the
NAME section only. It adds an option ‘K’ to man(1)to allow a crude full text search but it is not very efficient nor effective.
mandocdb
mandocdb [12] is part of the mdocml project andit is more in line with the goals of this project but
it takes a novel approach. It indexes the keywords
extracted from the man pages in a key-value store
using btree(3) [13]. It also comes with its own implementation of apropos which performs search using this key-value store. The key point of this implementation is that it exploits the semantic structure but rather than indexing the complete content,
it plucks out specific pieces of information fromthe man pages, for example author names, function
names, header file names, etc. It is more sophisticated and much more useful than classic apropos,
but it is still essentially a keyword lookup based implementation.

(nhitcount×w)
t f ← t f + (nglobalhitcount×doclen)
11:
end for
12: end for(t f ×id f )13: score ← (k+t f )14: return score

10:

5
5.1

Results7

Performance of apropos

Work on Ranking Algorithm
The ranking algorithm is based on the probabilistic
model of information retrieval [14]. It uses certain
parameters whose values are usually dependent on
the corpus and the search application. For example, certain weight parameters have been assigned
to different sections of man pages, signifying how
important the information in a particular section is
as compared to the rest of the sections. At the moment these values have been determined manually
but one goal is to use some supervised machinelearning techniques in order to automate this to improve the quality of search results further.

Listing 7, 8, and 9 show results of some of the sample
queries on new apropos to demonstrate how it performs
as compared to the traditional version. 1 In Figure
1, the spell corrector can be seen in action along withthe web interface that was developed using apropos-utils.

5.2

Performance of makemandb

On a modern desktop hardware, makemandb takes about
25 seconds to index 4000 man pages, and the size of
this index is 15 MB. When the number of man pages
is increased to 6100 by including some packages frompkgsrc, the time taken by makemandb grows to about 50
seconds and the size of the database index grows to 27
MB.

6

Future Work

Using external storage
A new feature is under development in Sqlite, tosupport external storage option in FTS databases.
This option would allow building the FTS index
without actually storing any content in the database
itself (except for the data required to maintain theindexes). This will save bulk of the disk space currently required by apropos database. The disk spacethus saved might also allow for experiments withranking algorithms which require storing additional
metadata on the disk.

Related Work

man-dbman-db [11] is a complete implementation of theman page documentation system and it is used on anumber of GNU/Linux distributions. man-db takes
an interesting approach for indexing the man pagedata. Unlike the classical apropos, it uses a Berkley8

$ apropos “add new user”
ssh-add(1)adds private key identities to the authentication agent...on the command line.
If any file requires a passphrase, ssh-add asks for the passphrase from the user. The passphrase
is read from the user's tty. ssh-add retries the last passphrase if multiple identity files are
given...
chpass(1)add or change user database information
add or change user database information
useradd(8)add a user to the system
The useradd utility adds a user to the system, creating and populating a home directory ifnecessary. Any skeleton files will be provided for the new user if they exist in the skel-dir
directory (see the k option). Default...
.
.
.

Listing 7: Add new user

$ apropos “make directory”
make(1) maintain program dependencies...CURDIR A path to the directory where make was executed. Refer to the description of PWD for
more details. MAKE The name that make was executed with argv[0]. For compatibility make also sets
.MAKE with the same value. The...
mkdir(1)make directories
make directoriesln(1)make links...a directory in which to place the link; otherwise it is placed in the current directory If
only the directory is specified, the link will be made to the last component of source_file. Given more than two arguments, ln makes...
mkfifo(1)make fifos
make fifos...of a=rw mkfifo requires write permission in the parent directory. mkfifo exits 0 if
successful, and >0 if an...
mkdir(2)make a directory file...will contain the directory has been exhausted. EDQUOT The user's quota of inodes on the filesystem on which the directory is being created has been exhausted. EIO An I/O error occurred
while making the directory entry or...

Listing 8: make directory$ apropos “signal number to string”
psignal(3)system signal messages...the signal number is not recognized sigaction(2) , the string Unknown signal is produced. The
psiginfo function produces the same output as the psignal function, only it uses the signal
number information from the si argument. The message strings can...
intro(2)introduction to system calls and error numbers...undefined signal to a signal(3) or kill(2) function). 23 ENFILE Too many open files in system.
Maximum number...shell. Pathname A path name is a NUL -terminated character string starting with
an optional slash, followed by zero or...
dump_lfs(8)filesystem backup...low estimates of the number of blocks to write, the number of tapes it...a string containing
embedded formatting commands for strftime(3). The total formatted string is...in. If dump_lfs
rdump_lfs receives a SIGINFO signal (see the status argument of stty...

Listing 9: signal number to string

9

Figure 1: The spell corrector and the CGI frontend in action

8

References

Availability[1] NetBSD manual page for the old version of apropos
http://netbsd.gw.com/cgi-bin/
man-cgi?apropos++NetBSD-5.1

The code for this project has been imported into the
NetBSD source tree and being maintained there. Experimental work is still being done in the github repositoryof the project. It can be obtained from:[2] NetBSD manual page for makewhatis(8)http://netbsd.gw.com/cgi-bin/
man-cgi?makewhatis++NetBSD-5.1

https://github.com/abhinav-upadhyay/
apropos replacement

9[3] Brin, S.; Page L. The Anatomy of a Large-Scale Hypertextual Web Search Engine Computer Networks
and ISDN Systems 30:107-117, 1998

Acknowledgement[4] Manning; Raghwan; Schutze Introduction to information retrieval, 3-9, 2008

This project has been developed as part of Google
Summer of Code 2011 [17], thanks to Google forsponsoring it. Special thanks to Kristaps Dzonsons
who is the developer of the mdocml [18] project, healso helped by pointing out several issues in the parsing
related code. Thanks to David Young who was involved
with this project closely and offered useful guidance andencouragement throughout. A special thanks goes toThomas Klausner who helped in writing and reviewing
the man pages for this project. Thanks to Petra Zeidler
for administering the GSoC program for The NetBSD
Foundation.

[5] Porter, M. F. An algorithm for suffix stripping, Program, 14(3): 130-137, 1980
[6] mdocml online manual page for libmandoc
http://mdocml.bsd.lv/mandoc.3.html[7] Sqlite home page
http://sqlite.org[8] Sqlite FTS3 and FTS4 Extensions
http://sqlite.org/fts3.html
10[9] Online manual page for makemandb(8)http://netbsd.gw.com/cgi-bin/
man-cgi?makemandb++NetBSD-current[10] Online manual page for apropos-utils(3)http://netbsd-soc.sf.net/projects/
apropos replacement/apropos-utils.html3[11] man-db, the on-line manual database
http://man-db.nongnu.org/[12] Online manual page for mandocdb(8)http://mdocml.bsd.lv/mandocdb.8.html[13] NetBSD online manual page for btree(3)http://netbsd.gw.com/cgi-bin/
man-cgi?btree+3+NetBSD-5.1[14] Fuhr, Norbert Probabilistic models in information
retrieval The Computer Journal 1992
[15] Zaragoza, H.; Craswell, N.; Taylor, M.; Saria, S.;
Robertson, S. Microsoft Cambridge at TREC13:
Web and HARD tracks In proceedings of TREC2004[16] Online manual page for man(7)http://mdocml.bsd.lv/man.7.html[17] Google Summer of Code home page
http://code.google.com/soc/[18] The mdocml project home page
http://mdocml.bsd.lv[19] Jones, Sparck K. A statistical interpretation of term
specificity and its application in retrieval. Journalof Documentation Volume 28 Number 1 1972 pp.
11-21[20] Salton, Gerard; Buckley C. Term-Weighting Approaches in Automatic Text Retrieval. Information
Processing & Management Vol. 24, No. 5, pp. 513523, 1988
[21] Online manual page for mdoc(7)http://mdocml.bsd.lv/mdoc.7.html

Notes
1 Although the new apropos by default returns 10 results for a query
but in the listings the output has been snipped to save space11