rc-list - mailing list for the rc(1) shell
 help / color / mirror / Atom feed
* man
@ 1993-05-21  4:38 Alan Watson
  0 siblings, 0 replies; only message in thread
From: Alan Watson @ 1993-05-21  4:38 UTC (permalink / raw)
  To: rc

The system supplied mans on Ultrix are awful: /usr/ucb/man is very slow,
especially across NFS, /usr/bin/man doesn't know about cat files, and
neither of them do the right thing with MANPATH.  I had been using a
hacked version of one of the later Berkeley mans, but it always left a
bad taste in my mouth -- finding, formatting, and printing a man page is
a perfect job for a shell script, so why was I using a binary?  This
came to a head when our system manager installed the perl man as the
system default.  It's about twice as fast as /usr/ucb/man (more so over
NFS), and understands MANPATH, but it still isn't exactly a snappy -- it
takes about a second to get going on a 5000/200, which is a noticeable
delay.

So, I set to work with rc, and managed to come up with a function that
is between three and four times faster than the perl version -- it gets
a man page up in a couple of tenths of a second.  The fact that my code
is less than a tenth of the size of the perl code gives me a warm
feeling inside -- small is beautiful, remember.

The single most important contributor to this responsiveness is the fact
that, unless we have to format the pages for the first time, there are
no execs in the function before you hit the `more' that outputs the man
page.  (I assume that echo is a built-in.)  None of the tricks I used
were new -- they've all appeared in the EXAMPLES file, although I'm sure
there will have been many independent discoveries of the two most
important techniques -- but I don't think I've come across a previous
example where avoiding external commands has had such a dramatic and
beneficial effect.  The fact that built-ins work so efficiently is a
testament to the superb quality of Byron's implementation, but none of
it would have been possible without Tom Duff's design, that is, do not
rescan!

Anyway, here's the code.  It understands `man -k', $PAGER, $manpath, and
sections like `1yp'; it doesn't understand any of the formatting
options.  Enjoy.

Alan.

fn apropos {

   if ( ~ $#* 0 ) {
      echo >[1=2] 'usage: apropos subject ...'
      return 1
   }

   manpath = $manpath pager = $PAGER {
      if ( ~ $#manpath 0 )
	 manpath = /usr/man
      if ( ~ $#pager 0 )
	 pager = ( page -s -u )
      subject = () for ( subject in $* ) {
	 {
	    whatis = () for ( whatis in $manpath^'/whatis' )
	       if ( ~ $whatis `{ echo $whatis^* } )
		  fgrep $subject $whatis
	 } | sed 's/^\.[A-Z][A-Z]//;s/^[ 	]*//' | sort -udf | $pager
      }

   }

   return

}

fn man {

   if ( ~ $#* 0 ) {
      echo >[2=1] 'usage: man [section] subject ...'
      return 1
   }

   if ( ~ $1 -k ) {
      shift
      apropos $*
      return
   }

   @ {

      # mansearch: look for man pages along $manpath.
      fn mansearch {
	 name = $1 section = $2 manpages = () dir = () for ( dir in $manpath ) {
	    if ( ~ $#section 0 ) {
	       manpages = $dir^'/man'^[1-8lnop]^'/'^$name^'.'^*
	    } else {
	       manpages = $dir^'/man'^[1-8lnop]^'/'^$name^'.'^$section
	    }
	    if ( ! ~ $manpages *^'[1-8lnop]'^* ) {
	       echo $manpages
	       return 0
	    }
	 }
	 return 1
      }

      # mantocat: convert /some/dirs/man1/foo.1 to /some/dirs/cat1/foo.1.
      fn mantocat {
	 manpage = $1 catpage = () sectionnumber = () {
	    ifs = ( / $nl ) { * = `{ echo $manpage } }
	    if ( ~ $manpage /* )
	       catpage = /
	    catpage = $catpage^$1
	    shift
	    while ( ! ~ $#* 2 ) {
	       catpage = $catpage^'/'^$1
	       shift
	    }
	    for ( sectionnumber in 1 2 3 4 5 6 7 8 l n o p ) {
	       if ( ~ $1 'man'^$sectionnumber ) {
		  catpage = $catpage^'/cat'^$sectionnumber
		  break
	       }
	    }
	    shift
	    catpage = $catpage^'/'^$1
	    echo $catpage
	 }
      }

      # manformat: check cat pages exists, and if not then create it.
      fn manformat {
	 manpage = $1 catpage = $2 catpages = () {
	    catpages = $catpage^*
	    if ( ! ~ $catpage $catpages ) {
	       cd `{ dirname `{ dirname $manpage } }
	       tbl $manpage | nroff -man | col >$catpage
	    }
	 }
      }

      # manoutput: output the cat page using $PAGER.
      fn manoutput {
	 pager = $PAGER {
	    if ( ~ $#pager 0 ) 
	       pager = ( page -s -u )
	    $pager $1
	 }
      }

      _status = 0 manpages = () manpath = $manpath {
	 if ( ~ $#manpath 0 )
	    manpath = '/usr/man'
	 while ( ! ~ $#* 0 ) {
	    if ( ~ $1 [1-8]* [lnop] ) {
	       if ( ~ $#* 1 ) {
		  echo >[2=1] 'usage: man [section] subject ...'
		  exit 1
	       } else {
		  manpages = `{ mansearch $2 $1 }
		  shift
	       }
	    } else {
	       manpages = `{ mansearch $1 }
	    }
	    if ( ~ $#manpages 0 ) {
	       echo >[1=2] 'man: cannot find man pages for '^$1
	       _status = 1
	    } else {
	       manpage = () catpage = () for ( manpage in $manpages ) {
		  catpage = `{ mantocat $manpage }
		  manformat $manpage $catpage
		  manoutput $catpage
	       }
	    }
	    shift
	 }
	 exit $_status
      }

   }

}


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~1993-05-21  4:38 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1993-05-21  4:38 man Alan Watson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).