[comp.sys.ibm.pc] MAN

richard@calvin.spp.cornell.edu (Richard Brittain) (02/26/90)

A few weeks ago there was a lot of discussion here about a "man" for msdos.
what was really wanted was a pd nroff which could handle -man macros.  Recently
an nroff subset called "ro" was posted to comp.sources.misc and although it
lacks many of the more advanced features on n/troff, it can handle simple
man pages quite well.  It needs some minor hacking to compile under TurboC 
(left as an exercise to the reader) plus a minor change to allow "-man" on the
command line instead of ".so tmac.an" in the body of the file.  
These macros will not format all man pages, but in my experience most man pages
are limited to a subset of the nroff commands and will format quite nicely.

Following this is my offering for MAN(1) written as a 4dos batch file.  It has
multiple "section" directories under a main "man" directory, sends output to
%PAGER if defined, and can handle compressed, zooed, zipped, arced, whatever
files, by associating an extraction process with a given file extension.
It also has a simple apropos option.


Richard Brittain,                   School of Elect. Eng.,  Upson Hall   
                                    Cornell University, Ithaca, NY 14853
ARPA: richard@calvin.spp.cornell.edu	
UUCP: {uunet,uw-beaver,rochester,cmcl2}!cornell!calvin!richard

------   tmac.an   man macros for "ro" -- cut here ---

..'  -man macros for "ro"
..'     These are not complete, and never will be since the real -man macros use
..'     advanced features of n|troff that ro does not have.  Nevertheless, they
..'     seem to do a fairly decent job on most man pages.
..'
.ig .\\\"
..'     Margins
.M1 4
.M2 2
.M3 2
.M4 4
..'     Line length 66, no justification, left margin 5+5
.ll 66
.na
.po 5
.in 5
..'     Tabs
.de DT
.ta 5
.em
..'     Section heading
.de SH
.sp 1
.ne 2
.in -5
\fB$0\fR
.br
.in +5
.em
..'     Sub-section heading
.de SS
.sp 1
.ne 2
\fB$0\fR
.br
.em
..'     Relative indent start
.de RS
.in +$0
.em
..'     Relative indent end
.de RE
.in
.em
..'     Paragraph break
.de PP
.br
.in 5
.sp \()P
.ne 2
.em
..'     Inter-paragraph distance
.de PD
.nr )P $0
.em
..'     Hanging paragraph
.de IP
.br
.sp )P
.in 5
$0
.ti +5
.in +5
.em
..'     Indented paragraph with hanging tag
.de TP
.br
.in 5
.sp )P
.ti +5
.in +5
.em
..'     Bold
.de B
\fR\fB$0\fR
.em
..'     Italics
.de I
\fR\fI$0\fR
.em
..'     Small text
.de SM
\fd$0\fR
.em
..'     Footers
.FO ^Page #^^(printed \n(mo/\n(dy/\n(yr)^
.DT
..'     Header
.de TH
.HE /\fB$0($1)\fR/$2/\fB$0($1)\fR/
.em
..'  Note -  no CR on last line or we don't get first page header
------------------------------ cut here -------------------

Here is my implementation of man(1) written as a 4dos script.  Don't try this
with command.com if you value your sanity.

-----------------  man.bat --------cut here ------------------

alias # REM
# !/bin/4dos  :-)
#
# 4DOS script to implement MAN(1)
#
# DESCRIPTION
#   All man entries must reside in section directories under a single man
#   directory  (default c:/man, or variable MANPATH).
#   If no section is specified in argument 1, all subdirectories are searched
#   by recursively calling this script.  The sections to be searched are listed
#   in %sections.
#   The script figures out what to do with each file based on the extension -
#   there should not be multiple files with the same name and different
#   extensions.  It is fine to have the same name in different sections
#   If a variable PAGER is defined, output is directed to this
#   program, otherwise output is to stdout.  To redirect the output of the
#   batch file, you have to redefine PAGER (sorry, cannot redirect batch
#   files)
#
#   If the first argument is "-k", subsequent arguments are searched for in
#   the file "whatis" if it exists.  Maintaining the whatis file is left as
#   an exercise to the reader.  There is only one whatis for all sections
#
#   Set %debug to any non-null value to get progress messages as the script runs
#
#                                       R. Brittain  02/25/90
setlocal
alias FINISH `endlocal ^ quit`
alias DEBUG  `if "%debug" ne "" echo "%&"`
if "%1" == "" goto usage                        ^# Check for arguments
set mandir=c:/man ^ set sections=1 2 3 4 5 6 7 8
if "%manpath" NE "" set mandir=%manpath
cdd %mandir                                     ^# Switch to the man directory
if "%1" == "-k" goto apropos                    ^# Check for -k option

# If only one argument, try all possible sections (subdirectories under here)
if "%2" == ""   goto recurse
goto next                                       ^# Jump to real stuff

:recurse
# No section specified, so recursively try each of the known subdirectories
# Test for file in each section before invoking, since recursive batch files are
# very slow
set recurs=TRUE                                 ^# Signal to child invokations
set found=

for %%sec in (%sections) do if exist man%%sec\%1.* call man %%sec %1
for %%sec in (%sections) do if exist man%%sec\%1.* set found=TRUE

# Only announce failure if no entries were found for ANY section
if "%found" == "" echo No manual entry for %1
FINISH                                          ^# End of recursive calls

:next
# We only get to here if we are being called with a section and command

cd man%1
DEBUG %cwd                                      ^# Descend into subdirectories
shift 1                                         ^# shift command into %1
if not exist %1.* goto notfound                 ^# check for file existance

# We seem to have an entry - construct a command based on the extension
# then run it.  Since alias expansion takes place before variable substitution,
# the constructed pipeline cannot use aliases

# Set appropriate LESS options here, just to make sure escape sequences are ok
set less=-merR

# Figure out what to do with the file, based on the extension
# If more than one matching file exists in the directory, the last one
# examined wins, but the results might be unexpected
# More extension-command pairs can easily be added here

set display= ^ set post=
dir /q %1.* | input %%filename                  ^# get actual filename
if exist %1.*z  set `display=zcat %1.*z`
if exist %1.1   set `display=ro -man %1.1 | termansi`
if exist %1.8   set `display=ro -man %1.8 | termansi`
if exist %1.1z  set `display=zcat %1.1z   | ro -man | termansi`
if exist %1.8z  set `display=zcat %1.8z   | ro -man | termansi`
if exist %1.zoo set `display=zoo xp %1.zoo`
if exist %1.arc set `display=pkunpak -c %1.arc`
if exist %1.zip set `display=pkunzip -c %1.zip`
if exist %1.nro set `display=notroff -pansi`

# append a pager if defined  (pager must be a single program, not a pipe, and
# must be able to read stdin).  Use "more" as default
if "%pager" == "" set pager=more
if "%display" NE "" set `post= | %pager`

# if no other command, do %pager alone, with input redirected from %filename
if "%display" == "" set `display=%pager <%filename`

:run                                            ^# Run the command
DEBUG %display %post
%display %post ^ FINISH

# Error messages
:usage
echo `Usage: man [-k | section] command` ^ FINISH

:notfound
if "%recurs" == "" echo No manual entry for %1 in %cwd ^ FINISH

:apropos
if not exist whatis goto nowhatis
if "%2" == "" goto usage                        ^# replace with your favourite grep
for %%i in (%2&) do find "%%i" whatis ^ FINISH

:nowhatis
echo No "whatis" file found in %cwd ^ FINISH

---------------------------- cut here ----------------

Richard Brittain,                   School of Elect. Eng.,  Upson Hall   
                                    Cornell University, Ithaca, NY 14853
ARPA: richard@calvin.spp.cornell.edu	
UUCP: {uunet,uw-beaver,rochester,cmcl2}!cornell!calvin!richard