#! /bin/sh
# the next line restarts using wish \
exec wish8.5 "$0" ${1+"$@"}
set manx(version) 2.2
set manx(mintcl) 8.4
set manx(mintk) 8.4
set manx(newuser) ""
set manx(mastermen) "/usr/local/man /usr/share/man /usr/X11R6/man"
set manx(masterbin) "/usr/bin /usr/local/bin /usr/X11R6/bin"
set man(zcat) "gzip -dcfq"
set man(compress) "gzip -q"
set man(apropos) {man -k}
set man(glimpse) "glimpse -z"
set man(glimpseindex) "glimpseindex -o -B -f"
set man(glimpsestrays) /tmp
set man(indexglimpse) "distributed"
set man(indexalso) ""
set man(texinfodir) ""
set man(gzgrep) ""
set man(rfcdir) ""
set man(format) {groff -Tascii -te -mandoc}
set man(printers) ""
set manx(dpis) "75 100"
set man(print) {groff -mandoc -Tps -te -l}
set man(cksum) cksum
set man(zlist) {gz z Z}
set man(co) co
set man(rlog) rlog
set man(rcsdiff) rcsdiff
set man(vdiff) diff
set manx(rman) rman
set man(catprint) ""
set man(catsig) {cat[^/]+(/[^/]+)?$}
set man(shortnames) 0
set manx(changes) {
1993
24 Mar	hard stuff working
25	easy stuff finished up, including documentation
29	wrote Makefile and otherwise prepared for distribution
31	changed incremental searching
1 Apr	posted to comp.lang.tcl (698 lines; 536, excluding instructions)
2	more portable version posted
	browsers `send' to `manShowManFound', sink manual section
4	SEE ALSO links filter, unpacks compressed pages (both inspired by Paul Raines)
5	manX.[zZ] directories, whatis found in text
6	workaround for bind bug, sunken text (both Dan Schenck)
	"Searching for ..." message
7	print: now meta-click, works with compressed ones
	fixed bind problems
	can type in, e.g., print.3v and print.3s; distinction saved in history
	.so links work (thanks Dave Lemke)--but don't do this with compressed pages (which HPs don't)
	various portability/system admin (suggested by model bug reporter Lars Huttar)
8	memory pipe replaces tmp file
10	Emacs-like point and mark
	sections loaded on demand (suggested by Lars Huttar)
	user additions preserved in ~/.tkman 
	quick view of first n lines
11	>1000 lines
	wait cursor, tkinfo shares window with TkMan
12	option to preload or not, instant show update moved to bs2tk
13	restricted search of paths in MANPATH (anthony baxter)
14	case sensitivity switches to searches (anthony baxter)
15	tbl, eqn handled (Mark McIntosh)
17	incremental searching made more like Emacs, flush volume cache (both suggested by Robert Wilensky)
19	fixed handling of compressed pages, section re-viewing much faster
20	solution to multiple, identically-named man pages in different directories, at the expense of volume load on demand
25	different way to deal with multiples
27	hack around Tk text's wordend limitation
29	compressed database hack around
	v1.3.3 released
30	dups menu hangs around, different hack around for compressed database
2 May	faster startup with database (big thanks to Frank Delahoyde)
	SuperMan, of dubious value since it's so slow (suggested by Larry Virden)
5	demo to UCB Tcl/Tk users
7	(none) and (n/a) shown when pulldowns empty (Steve Smoot)
14	manTextOpen, manTextClose, manSectButt
	documented: scan, pipe capability of apropos
	apropos responsive to selected directory switches (Robert Wilensky)
15	more generous focus hits (Steve Smoot), tab moves focus
18	v1.3.4 released
19	v1.3.5 released (fixed bug which affected first-time users)
	default fonts changed from pixel specification to point size (Donn Cave)
29	man page name searching case insensitive--search time 3->4 seconds (Wayne A. Christopher)
1 Jun	multiple instantiations
2	output menu for multiple instantiations
	changed default font to New Century Schoolbook so underscores show up
4	switch all man paths on or off (David Taubman)
7	. and .. to ~ and / (John Hagerman)
25	support for people with only cat directories (6 characters from Mike Beasley)
	v1.4 released
28	deleted "focus $w.show" at very end of proc TkMan.  otherwise if start up iconified, then deiconify before done with init, text window doesn't show up. It's the focus problem again.  (David Svoboda)
29	"update, don't quit" (Gordon Lack & Lord Wodehouse)
1 Jul	lengthier criteria for picking which to show from list of matches (Michael Moore and Kwo-Long Lai)
14	option not to move change bars, apropos filter in variable (both Warren Jessop)
18	manKeyNav's key bindings to variables (David Sibley; thanks Wayne Christopher)
	moved Paths, added `All' to Volumes (Neal McBurnett, friend of Scott Schwartz)
	option to save nroff-formatted version (Warren Jessop)
24	margins around text box (colleague of Gordon Lack)
26	character to indicate popup menu (too bulky and unaesthetic, though)
27	keep list of man pages with dots--startup takes a couple more seconds (Warren Jessop)
4 Aug	check to see if man page source is older than nroff (Warren Jessop)
	C-s C-s retrieves last search pattern, as in Emacs
5	multiple instantiations share menu windows--sabotaged by new requirement in Tk 3.3
6	each instance gets own set of variables
	`|command' syntax for arbitrary text-generating command, `<file' syntax for reading raw file
	uses SearchBox mega widget
8	file name completion (if had fast database could do man page name completion and spelling correction)
11	user annotations (first cool new idea since March!) (could have set of different annotations but would that be useful?) (automatically jump to first highlight?)
17	mandesc-like directory dance hall (clamored for by Oyvind Yrke)
	>2000 lines, 70K characters, despite kicking generally useful code into taputils.tcl
	decision: don't integrate tkinfo (it could use the searchbox megawidget, though)
20	changes to tkmandesc (Oyvind Yrke)
21	SGI support worked out (Paul Raines)
13 Sep	greater control of ordering of added (pseudo) volumes (Paul Raines)
15	submitted to comp.sources.testers
	>80K characters
20	fixed printing of .so pages (Larry Virden)
21	various parts of ui disabled for different text box content types
28	1.5 review version available via comp.sources.testers
7 Oct	iconposition, -nosave, tkmangeometry (Chris Siebenmann)
12	reviews received from comp.sources.testers
	C-d/C-m hot keys (Kwo-Long Lai)
	variety of small changes suggested by the anonymous reviewers
	removed gzip requirement for H-P
	if main window owns X selection, zap it before showing another page
13	taking advantage of bs2tk's new reverse compile, do this for cat page printouts
	show hot spot on a single click (many, Robert Wilensky first)
	more small changes suggested by reviewers
	killing TkMan with window manager's kill removes process
21	>90K characters
24	highlights for symbolic links resolved to physical file
2 Nov	1.5 released for Tcl 7.0/Tk 3.3
24 Dec	TKMAN environment variable sets usual options



1994
1 Jan	support for LANG environment variable (Yasuro Kawata)
21	support for saving to H-P's cat.Z (w/o .Z/.gz/.z suffix)
28	fixed deep weirdness, write protected home directory bugs (Dave Glowacki)
1 Apr	first anniversary
12 May	list of all man pages with highlights (Steven S. Dick)
23	help page maintained in HTML, compiled to Tk text and [tn]roff (can zap linebreaks so get good linebreaking on all screen sizes!)
5 Jun	would like to use idiom like: menubutton -menu [set m [menu $w.x.m]], but have to do this: set m $w.x.m; menubutton -menu $m; menu $m
6 Aug	experiment in moving database to Glimpse
10	compressed list of all man page names works great: < 40K in size (with gzip), quick to search (preserves pattern matching), since kept on disk reduces startup time and memory image runs off tkmandesc orderings so can still do wild additions, section dumps efficient
24	search within virtual sections too
	finds names with dots (again)
26	incremental search highlights match
	try to find needed binaries beforehand, abort if can't (Keith Vetter among others)
1 Sep	support for weird /etc/man.conf (Shannon Jaeger)
	dynamically change font dpi
4	handle .so links to compressed pages (grr)
6	validity checks on components of MANPATH
9	hookup with Glimpse for fulltext search only (& optionally)
12	1.6beta testing
16	glimpse AND apropos, both now dumping results into a pseudo volume
	Perl's out, only Tcl for formatting volumes... sigh
17	automatically rebuild database every month
22	if current mandir != mandir used to build database, automatically rebuild it
26	automatically rebuild database if change in MANPATH or tkmandesc commands
27	-rebuildandquit option (Dietmar Theobald)
	instead of monthly rebuilds, simply check dates of mandirs--it takes a noticable amount of time, but not excessively long (Dietmar Theobald)
29	Volume lists dynamically created, once again controlled by Paths (push from Kevin L. Short)
	database validity check information moved into .tkmandatabase
30 Sep	1.6gamma testing
7 Oct	use simple priority number to choose better the right manual page (why didn't I think of this before?)
31 Oct	list of new/changed manual pages, if any, as pseudovolume
	when looking at header&footer, show date of file also
7 Nov	support for keeping Solaris 1, 1b, 1c, ... volumes separate (Will C Lauer)
10&11	preferences panels (code now >100K characters, >3000 lines)
21	Support for proposed Linux FSSTND /var/catman
23	deep-six the problematic mandir variable and suck up all unique names in manN*/* and catN*/* assuming they're in manN*/* => takes to long to build database
25	abolished mandir variable (which so many didn't set correctly)
	if no manN, check for catN automatically.  lose on stray cats, though
29	manDescAdd also makes that directory available to Glimpse
	Tcl code indention: spaces => tabs, saving 9K
7 Dec	1.6delta testing
8	IBM AIX support: first need to convert InfoExplorer files to /usr/man/cat*. can't parse pages (so don't), so lose on Sections, Links.  but everything else OK
9	restored SGI support (oops!)
15	bad variable values in old save file automatically updated (Martin Forssen & Greg McFarlane)
17	"(none)"'s changed to -state disabled's (don't have someone try it and fail)
20	pulldown menus shrink as necessary to fit on screen, if possible (Marty Leisner)
22	Winter Solstice: 1.6 released for use with RosettaMan + new database
	(100th RCS revision, 3628 lines)
24	updated for Tcl 7.4/Tk 4.0
29	new idiom for menubuttons + menus



1995
1 Jan	time to display page once found cut by more than a third by (1) changing while {[gets $fid line]!=1} {eval $line} to while {![eof $fid]} {eval [gets $fid]} and (2) hacking tkText.c to accept multiple (text,tags+mark) pairs
20	right pseudosection set for Shortcuts
24 Mar	tweaks to Glimpse, site-wide installation (John Talintyre)
25	changes for Tk 4.0b3: tk colormodel, -nocase (grr, no easy marks for text widget)
1.7b1	released for Tcl 7.4b3/Tk 4.0b3
26 Apr	chmod a+r for Glimpse indexes (except those in one's home directory) (Jim Ingham)
29 Jun	1.7b2 released for Tcl 7.4b4/Tk 4.0b4
30	1.7b3 released to fix some egregious bug or something
21 Jul	1.7 released for Tcl 7.4/Tk 4.0
	Preferences' Defaults button applies to current panel only (Don Libes)
26	1.7.1 released, advertised widely
1 Aug	miscellaneous small fixes, columns for apropos
	>4000 lines (happened sometime earlier)
	1.7.2 released to fix problem in passing command line options
9	added manDescSGI to place catman directories into user-added volumes according to user-specified patterns (Scott Nelson).  Is this a final solution to the SGI issue?
11	only reset gui if something changed in Preferences
	1.7.3b2 advertised to SGI users
18	option to present subvolumes as submenus under Volumes (original version by Nigel Wade)
	1.7.3 released
24	special case for `whatis' file check on dumb BSDI (John Carroll)
10 Oct	1.7.4 released
2 Nov	1.7.5 released
2 Dec	compensate for varying behavior of sed from flavor to flaver (Vin Shelton)
20	place man page name in window title (Simon Blanchard)



1996
16 Jan	option for unified Glimpse index
31	fix up picking right file when have match both with and without extensions (Carl Mascott)
6 Feb	small changes to take advantage of new features in Tcl 7.5/Tk 4.1 (foreach, tag prevrange)
11	use clock command instead of exec date
12	final comb through of code to clean up any lingering cruft
	take links from manref tags, fixed manBinCheck on fully-specified paths
20	fixed man.conf support (Hagen Finley)
1 Apr	statistics and information screen
26	fix check for out of date Glimpse indexes (Vinnie Shelton)
13 May	option for single-click hyperlinks (someone in CS160--identify yourself for an acknowledgement)
26	try to reattach highlights to right positions when man page changes
27	5000 lines
 3 Jun  searches give warning before wraparound (Rick Macdonald)
20	choose print destination from a list of printers (Peter Maguire)
23	menu of command line options in each section (maybe not such a good idea after all)
10 Jul  automatically set special case bindings files for virgins on Solaris, SGI, SCO
16	fixed bug related to find and the recent page list that caused inordinately long database build times on some systems (Vinnie Shelton)
19	cumulative statistics recording without afffecting other persistent settings
 5 Oct  dispense with stray cats problem by groking man and cat directories for pages (with only a slight increase in database build time)
22	speed up SGI startup (Paul Raines)
 7 Nov	1.8 released
11	FSSTND directory /var/catman configurable, to one's home directory, say (Bryan M Kramer)
20 Dec  update for Tcl/Tk 8.0: tweaks for compiler, rework fonts
25	speed up database builds by 40% by not checking mtime for every file (how did that happen in the first place?)



1997
 4 Jan	record number of times each page is seen
 7	1.8.1 released
 8	collapse/outline sections
13	2.0a1 released
15	database build time cut in half(!) or more by obviating need to exec helpers
	2.0a2 released
16	just keep database in memory, build at every startup, like xman.  Fast enough if just glob, and can search reasonably quickly with new Tcl lists.  No more .tkmandatabase cluttering up the HOME directory, and no hassle with multiple databases for multiple machine architectures.  Lose shared database, however.  Retain recent section, which is time consuming to compute, by using "after threading".
	2.0a3 released
17	thread manBinCheck
	man page name completion
19	highlights follow along if page, i.e. file, moved
	GNU info reader (of source), a good application for outline viewer
 9 Feb  highlights always/at first/never visible in collapsed outlines
17	if old version of page under RCS, show differences (additions, deletions, changes)
11 Apr	2.0b1 released
27 May  updated for Tcl/Tk 8.0b1
29	view arbitrary file with tk_getOpenFile (Jeffrey Hobbs)
25 Jun	simple support for RFC (dump rfc-index.txt, hyperlinks for id numbers)
 5 Jul	realigned invisible text patch for Tcl/Tk 8.0b2
	if can't find manual page in user's MANPATH, try looking in system master list; likewise for corresponding binaries
23	condensed GUI
26	autoshow (search for and make NoteMarks of) certain words
	long lines (groff's .ll pointed out by Marco Melgazzi)
10 Aug	fuzzy search for man page names (trivial once you think of it)
17 Sep 	2.0 final released
27 Oct	2.0.1 released
	rebus
	2.0.2 released
 2 Nov  sidebar of section, highlight, search
 4 Nov	2.0.3 released
	let PolyglotMan do heavy (time-consuming) lifting for NoteMarks, rebus
	autosearch backgrounded
	=> above two changes greatly speed up initial page viewing
30 Nov	2.0.4 released
20 Dec	regexp search within Texinfo (without glimpse, though need tight tolerences to make it work well)
30 Dec	2.0.5 released



1998
11 Feb	2.0.6 released
20	glimpse across Texinfo
 3 Apr	sped up Texinfo formatting by processing much with regsub before stuffing text info buffer
12	save nuanced definition of last scroll position as Notemark
 8 May	indent Texinfo contents according to hierarchy level (Axel Boldt)
13 Jul	2.1b1 released
 7 Aug	>10000 lines, or more than 18X the lines of code of version 1.0
20 Nov	2.1b2 released.  Final version for Tcl/Tk 8.0 (subsequent versions take advantage of Tcl/Tk 8.1's new regular expressions and other new features)



1999
22 Jan	convert to Tcl 8.1 regexp
27 Jun	run through TclPro Checker; almost all warnings suggest putting arg of "if" or "catch" in braces
 4 Jul	show stray cats as warnings
27 Jul	ugh, SGI also installs .Z (Jan Martin)
24 Aug	2.1b3 released for Tcl/Tk 8.1 and 8.2
23 Sep	support Solaris 7's SGML documentation natively
10 Nov	Windoze port... which works if you have all cygwin installed

2000
29 May	volume names for Solaris 8 added (Jongki Suwandi)
22 Jun	2.1 released for Tcl/Tk 8.3--which has incorporated the elided text patch

2003
12 Mar  updated for Tcl/Tk 8.4
 1 Apr  Tenth birthday.  Version 2.2 for Tcl/Tk 8.4 released.
}
proc manHelpDump {t} {
   $t insert end {A Bird?  A Plane?  TkMan!  (TkPerson?)

 by Tom Phelps 

implemented in Tcl/Tk 8.4
 TkMan icon drawn by Rei Shinozuka
 many other icons taken from the AIcons collection
Compatible with Sun Solaris, SunOS, Hewlett-Packard HP-UX, OSF/1 aka Digital UNIX, DEC Ultrix, AT&T System V, SGI IRIX, Linux, SCO, IBM AIX, FreeBSD, BSDI -- each of which, believe you-me, is in some way different from all the others 

The latest version of TkMan is available via http://tkman.sourceforge.net.

Before reporting a bug, first check the home site to make sure you're using the latest version of TkMan.  If you want to change how a feature works, first check the Preferences dialog. If you send me bug reports and/or suggestions for new features, include your MANPATH, the versions of TkMan, Tcl, Tk, X, and UNIX, your machine and X window manager names, the edited Makefile, a copy of your ~/.tkman file, and the first few lines of the tkman executable.  I'd also be interested in learning where you obtained TkMan.  Send feedback to phelps@ACM.org 


Abstract

TkMan is a graphical, hypertext manual page and Texinfo browser for UNIX. TkMan boasts hypertext links, (optional) outline view of man pages, high quality display and superior navigational interface to Texinfo documents, a novel information visualization mechanism called Notemarks, full text search among man pages and Texinfo,  incremental and regular expression search within pages, regular expression search within Texinfo that shows all matches (not just the next), robustly attached yellow highlight annotations,  a shortcut/hot list,  lists of all pages in user configurable volumes,  a comprehensive Preferences panel, man page versioning support, and unmatched online text formatting and display quality, among many other features.  


Introduction

"I encourage you to use TkMan for reading man pages. ... TkMan provides an extremely pleasant GUI for browsing man pages.  I cannot describe all the nice features of TkMan in this small space.  Instead I will merely say that I now actually look forward to reading man pages as long as I can do it with TkMan."
 -- Don Libes, Exploring Expect, page 21 

TkMan offers many major advantages over man and xman: hypertext links to other man pages (click on a word in the text which corresponds to a man page, and you jump there), and better navigation within long man pages with searches (both incremental and regular expression) and direct jumps to sections of a page.  TkMan also offers some convenience features, like a user-configurable list of commonly used man pages, a one-click printout, and integration of  apropos. 

Furthermore, one may highlight, as if with a yellow marker, arbitrary passages of text in man pages and Texinfo and subsequently jump directly to these passages by selecting an identifying excerpt from a pulldown menu.  (Highlights are robust across changes to page content and movement of the file.)   Pages are optionally given an outlining user interface whereby the text of a section can be collapsed or expanded underneath its header, independently of other sections.  Within otherwise collapsed sections, a variety of Notemarks(TM) can appear.  Notemarks are excerpts from the text showing highlighted text, command-line options, search results, or an excerpt of each paragraph in that section,  shown in context with section headers and other Notemarks. Functioning as a note, a Notemark may itself communicate sufficient information; functioning as a bookmark, it can be clicked on to automatically expand the corresponding section and scroll to that point.  Notemarks densely display numerous immediately available hooks into long texts to expedite identification of a desired passage. 

The Texinfo browser takes a very different approach than any other GNU info brower, and thereby is able to provide a number of advantages not possible in an info-only browser.  (1) TkMan's browser works from the Texinfo source, as opposed to a compiled form that has been formatted for character terminal displays, and therefore can and does provide much better looking text, in multiple fonts (proportionally-spaced for body text, typewriter for computer text, bold and italics, blue hyperlinks for crossreferences, and even a cedilla and a lowered E in TeX).  (2) An outlining interface that continuously gives overview and context to navigation within the document, as opposed to the system of nodes with only immediate neighbors known (next, previous, parent), which, at least for me, very quickly leads to being "lost in info-space".  All this costs disk space of only 2% over the original Texinfo source files, which themselves may be compressed. 

Other features include:
 * full text search of manual pages and Texinfo (with Glimpse)
 * individualized directory-to-volume collection mappings
 * if an old version of the page is available under RCS, optionally show differences: additions as italics, deletions as overstrike, changes as bold italics
 * when multiple pages match the search name, a pulldown list of all matches
 * regular expression searches for manual page names
 * man page name completion
 * when searching for documentation, try Texinfo names too, and   optionally) prefer Texinfo documentation to man page
 * Fuzzy search for man page names if not exact match found   (e.g., "srcolbzart" finds "scrollbar")
 * list of recently added or changed manual pages
 * "history" list of the most recently visited pages
 * preferences panel to control fonts, colors, and many other system settings
 * compatibility with compressed pages (both as source and formatted)
 * diagnostics on your manual page installation
 * helper script retkman that can be used to restart TkMan after changes to the MANPATH in a shell, as from a "package" manager
 * in man page display, elision of those unsightly page headers and footers
 * and, when attempting to print a page available only in formatted form, reverse compilation into [tn]roff source, which can then be reformatted as good-looking PostScript. 


Using TkMan

In the text that follows, click means a quick mouse button click (down and up in less than a quarter of a second), and press means press and hold down the mouse button.  Some widgets in the interface function as buttons when given a click, menus if pressed.  If you want to access the menu, you do not need to wait for the menu itself to appear before dragging down the menu; go ahead and drag down with the mouse, and the interface will catch up to the mouse movement when the menu appears.  You still post menus, by waiting until the menu appears and then releasing the button with the cursor over the menubutton. 


Locating a man page

There are several ways to specify the manual page you desire.  You can type its name into the entry box at the top of the screen and press Return or click the man button.  The name may be just the name of the command or may end with .n or (n), where n specifies in which section to look.  Type in a partial name of three or more letters and type Escape to invoke page name completion. If there was exactly one match, the letters typed in so far will be replaced by the name of the page and its section number; otherwise it will be the longest common prefix of all possible matches. Man pages are matched using regular expressions, so you can use . to match any single character, * to match any (zero or more) of the previous regular expression, [ .. ] to match any single character in the enclosed class; see regexp.n for more information.  For instance, .*mail.*.1 searches section 1 (user commands) for commands with "mail" anywhere in their names. Likewise, one can collect all the various manual pages relating to Perl 5 with perl.*, or see a list of all X window managers with .*wm. If you're running TkMan from a shell and giving it an initial man page name to load up as an argument, use this syntax (adequately quoted for protection from the shell), as opposed to the syntax of the standard man command (which is man section name--that is, the section number comes first, whereas in TkMan it is part of the name. You can specify an initial section of the page to examine by appending to the name a / and a search expression that matches part of a section name; for example,  csh/diag  opens and scrolls to the Diagnostics section of csh immediately upon loading that page. Similarly, appending to the name a question mark and a search pattern will invoke a full text search in the page once it is brought up. 

Whenever you have a man page name in the text display box, whether from apropos, a volume listing or a reference within another man page, you can click on it to hypertext-jump to it.  In point of fact, man pages do not explicitly code man page references, but words that are especially likely to be references are distinguished, though any word may be clicked on to treat it as a man page reference.  Pressing shift while clicking opens up a new viewer box to display the page. 

Usually TkMan searches the colon-separated list of directories in your MANPATH environment variable for the man page, but you may instead provide a path name for the man page by beginning it with  `~', `/', `.' or `..'; this is the way to access a man page which isn't installed in a MANPATH man directory.  File name completion is invoked with Escape. Further, other Tcl interpreters may display a man page in TkMan by sending a message to the function manShowMan with the name of the desired man page, e.g. send tkman manShowMan tcl.n.  If multiple man page names match the specification, the first match (as searched for in MANPATH order) is shown and a pulldown menu appears which contains a list of the other matches.  Return from reading help or a volume listing to the last man page seen with C-m when the focus is in the main text display area. 

apropos information is available by typing the name and hitting Shift-Return or pressing on the man button and dragging down to apropos. The output of apropos is piped through sort and uniq to remove duplicates.  To pass the matches through additional filters, simply give the pipe as in a shell, e.g., `search | grep ^g' (each space character is significant) returns all the search-related commands which begin with the letter g. TkMan relies on the native system to supply apropos information and on some but not all systems (HP-UX but not GNU, for instance), apropos information for all pages in a given section is available by giving the section number in parentheses, e.g., (1) as the apropos search string. 

If it's installed, you will see  in the man menu an entry for full text searching with glimpse. Fuzzy full text is a full text search that finds the "best match" in the absence of an exact match (it uses glimpse's -B option). Glimpse was written by Udi Manber, Sun Wu, and Burra Gopal of the University of Arizona's Department of Computer Science. Glimpse requires only small index files ("typically 2-5% the size of the original text" but larger percentages for smaller amounts of text).  In their performance measurements, "a search for Schwarzkopf allowing two misspelling errors in 5600 files occupying 77MB took 7 seconds on a SUN IPC".  For example, one may search for the string WWW anywhere in any manual page by typing in WWW in the entry line at the top of the screen and clicking on the glimpse button or typing Meta-Return. Escape and C-g can interrupt a search after the current directory is done. To employ glimpse's command line options, simply place them before the search pattern in the entry box, or add them to the default options by editing the man(glimpse) variable in your ~/.tkman startup file (see Customizing TkMan, below). For instance, to search for perl as a full word only and not as part of another word (as in "properly"), case insensitively, glimpse for -wi perl.   Glimpse supports an AND operation denoted by the symbol `;' and an OR operation denoted by the symbol `,'. For example, to search for "insert" and "text" in Programmer Subroutines (volume 3), glimpse for -F \\.3 insert;text. Refer to the glimpse manual page for more information. Note that searching is done on man page source, and that the number of textual excerpts is limited to five per page to guard against frequent hits in a file unbalancing the search, but this means the text you want might be in that page and just not shown in an excerpt. The regular expression used by glimpse automatically sets the intrapage search  expression.  For this reason, the case sensitivity of the glimpsing is set to the same as intrapage regular expression searching. A complete set of matches from the last full text search is available under the Volumes menu.  Searching is done in manual page and Texinfo source, and the matches displayed in the formatted versions, so it is possible to match on formatting or in comments and not have any matches in the formatted version. 

The Paths submenu under the man menu (press and hold down mouse button  on man and drag down, then across)  gives you complete control over which directory hierarchies of your MANPATH are searched for man pages and apropos information.   If you plan more than a couple of operations with this menu, consider tearing it off by releasing the mouse on the dashed line at the top of the menu. If you use a "modules" system to manage software--binaries and their accompanying documentation--that as a side effect changes the MANPATH,  you can update TkMan by typing retkman (see below) in any shell.   

You can call up a listing of all man pages in a volume through the Volumes pulldown menu and then select one to view by clicking on its name. New `pseudo-volumes' can be added, and arbitrary directories may be added to or deleted from a volume listing using tkmandesc commands, described below. In a volume listing, typing a letter jumps to the line in the listing starting with that letter; capital and lower case letters are distinct.   Other special collections are placed in Volumes.  Texinfo and Request for Comments display such lists.  Recently added/changed presents a list of man pages whose time (specifically, ctime) is within the last couple weeks. The title of the Volume menu reflects the current menu, and that volume listing may be quickly recalled by clicking that title button or by typing C-d. 

The last few man pages you looked at can be accessed directly through the History pulldown menu, which is the circular arrow to the right of the name typein box.   The list is sorted top to bottom in order of increasing time since that page was last visited. The Shortcuts menu, the x/+/- to the right of History,  lists your personal favorites and is used just like History, with the additional options of adding the current man page (by clicking +) or removing it (-) from the list.   

(Man pages specified as above are processed through an nroff filter. TkMan can also read raw text from a file or from a command pipeline, which can then be read, searched and highlighted same as a man page.  To read from a file, make the first character in the name a <, as in <~/foo.txt.  To open a pipe, make the first character a | (vertical bar), as in `|gzcat foo.txt.gz' or `|cat ../foo.txt | grep bar' (that's no space after the first |, a space before and after any subsequent ones). After reading a file in this way, the current working directory is set to its directory. Commands are not processed by a shell, but the metacharacters ., .., ~ and $ (for environment variables), are expanded nonetheless.  Typing is eased further by file name completion, bound to Escape.   Lone files (i.e., not part of a pipe) are automatically uncompressed--no need to read compressed files through a zcat pipe. ) 


Working within a man page

The invisible text patch to Tk's text widget enables outlining.  Page section and subsection content can be collapsed and expanded by clicking on the corresponding header.  Opening a section by clicking on its title moves its section title to the top of the screen save for five lines: to the top in order to immediately show the initial text of the section, and save for five lines in order to maintain some orienting context.  Clicking button 3 anywhere in that section toggles its state.  This makes it convenient to expand a section, scroll through it a bit, and then close it up to return to the header overview.  Double clicking button 3 closes up all sections.  Outlining can be tuned, even turned off, via the Preferences dialog under the Occasionals menu (called ...). Outlining doesn't interfere with jumping to a section via the Sections or Highlights menus or during searching, as sections automatically open up as needed.  (Try this: go to text.n and do a regular expression search for pathName; hit <Return> twice.) When mousing about in the text collapsing and expanding sections, a more convenient way to scroll than moving back and forth to and from the scrollbar is to use the keyboard or to drag with button 2 in the text. When a page is displayed as an outline, the number to the right of the section head is the number of lines in that section.  Regular expression searches change this number to the number of hits in that section. 

To the extent it follows conventional formatting, a manual page is parsed to yield its section and subsection titles (which are directly available from the Sections pulldown--the leftmost menu, which appears as a page icon)  and references to other man pages from throughout the page including its SEE ALSO section.   One may jump directly to a section within a man page  by selecting the corresponding menu entry. 

Within a man page or raw text file or pipe, you may add ad hoc highlighting, as though with a yellow marker (underlining on monochrome monitors).  Highlighted regions may then be scrolled to directly through the Highlights pulldown menu.  To highlight a region, select the desired text by clicking button 1, dragging to the far extent of the desired region and releasing the button; Hi changes to a + to indicate that clicking it will highlight that span.  On subsequent text selections, if the selection overlaps one or more existing highlights, Hi changes to a -, indicating that clicking it will remove those highlights.  To remove all the highlights over a large area, close those outline sections and select across collapsed text before clicking -. A shift-click on the menu title tours through all the highlights on the page. A complete set of pages with highlighting is available under the Volumes menu. 

Highlighting information is robust against changes to and reformatting of the page.  Thus you can justify expending some effort in marking up pages with the knowledge that if a man page does change, as when the corresponding software package and its documentation are updated, TkMan will try to reposition them to the corresponding positions in the new pages.  The success of the algorithm can be measured by comparing the "highlights repositioned automatically" vs "highlights unattachable" statistics under Occasionals/Statistics and Information. As of this writing, my personal statistics report that 6866 highlights have been reattached without incident, 614 have been automatically repositioned on a changed page, 38 have been automatically carried forward to a moved page, and a mere 7 were unattachable. Moreover, highlights follow a page if it is moved.  If the current page has no highights and its name matches that of a page with highlights that no longer exists, then what probably happened is that the page was moved and you are asked whether this is indeed the case and thus whether to reassociate the highlights to this new page. Thus, say you have highlighted a number of pages in Tcl 7.6/Tk 4.1. Updating to Tcl/Tk 8.0 will both reassociate the annotation set to the new file name and reposition the annotations within the page--all automatically, asking for permission first. 

Here's how highlight reattachment works. When you highlight a region, the starting and ending positions are saved along with some of the content of the highlighted region and context.   When that page is viewed again, if those positions still match the context, the highlight is attached there (this is an exact match).  If not, the context is searched forward and backward for a match, with the closer match chosen if there are matches in both directions (a repositioned match).   If no match is found with the full context, gradually less and less of it is tried,  reasoning that perhaps the content of the context has been changed (repositioned, but with less confidence, triggering a warning dialog). If still no match is found (an orphan), the highlight is reported at the bottom of the page, where it must be reattached manually before leaving the page or it will be forgotten.  (With TkMan v1.8b3 and earlier, highlights were attached by positions only, and when the page modification date changed, the user had the choice of applying  highlights at those same positions regardless of the text there now or throwing out the highlights wholesale.  Old style highlights are automatically updated to the new style that can be automatically and robustly repositioned.  The next time an old style page is viewed, the old style highlights are applied as before, and from those positions new style highlights are composed.)  The annotation reattachment mechanism is inspired by Stanford's ComMentor system and, post facto, Larry Wall's patch. 

You can move about the man page by using the scrollbar or typing a number of key combinations familiar to Emacs aficionados.  Space and C-v page down; delete and M-v page up.  Return pages down, expanding collapsed outline sections as it encounters them. (vi fans will be happy to hear that C-f and C-b also page down and page up, respectively.) C-n and C-p scroll up and down, respectively, by a single line. M-< goes to the top and M-> to the bottom of the text.  One may "scan" the page, which is to say scroll it up and down with the mouse but without the use of the scrollbar, by dragging on the text display with the middle mouse button pressed.  Like Emacs, C-space will mark one's current location, which can be returned to later with C-x, which exchanges the then-current position with the saved mark; a second C-x swaps back. Following an intradocument hyperlink in Texinfo automatically marks the location of the link source. 

C-s initiates an incremental search.  Subsequently typing a few letters attempts to find a line with that string, starting its search at the current match, if any, or otherwise the topmost visible line.   A second C-s finds the next match of the string typed so far.  (If the current search string is empty, a second C-s retrieves the previous search pattern.) C-r is similar to C-s but searches backwards. Escape or C-g cancels searching. Incremental search can be used to quickly locate a particular command-line option or a particular command in a group (as in csh's long list of internal commands). 

The document map runs alongside the scrollbar.  It has various marks at positions proportional to their position in the document. White bars indicate section and subsection heads, setting the major divisions.  Blue indicates hyperlinks.  Yellow indicates highlights. Orange indicates search hits.  You can click on the document map to scroll to that part of the document, opening the corresponding outline section if necessary.  The document map gives a quick sense of the structure or the page.  I've found it especially useful in display the distribution of search hits. 

At the bottom of the screen, type in a regular expression to search for (see Tcl's regexp command), and hit return or click Search to begin a search.  In the outline view, this closes up all sections and displays the number of hits in each section alongside the corresponding section title. At this point, you can open up a particular section that seems particularly relevant, or keep hitting return to cycle through all matches. Hit C-s or click the down arrow to search for the next occurrence, C-r or the up arrow for previous occurances. 

To quickly search for the current selection, set in any X application,  click Meta-Button-1 or Alt-Button-1 or Control-Button-1 (pick one that doesn't conflict with your window manager) anywhere in the text display.  If no selection is set, the search is made for the word under the cursor. 

The Tab key moves the focus from the man page type-in line to the text view of the man page to the search line and back around.  Shift-Tab jumps about in the opposite direction. 


Other commands

The Occasionals menu, labeled ... at the extreme right,  holds commands and options which you probably won't use frequently.  Help returns to this information screen.  Although virtually made obsolete by TkMan, Kill Trees makes a printout of the current man page on dead, cut, bleached trees, helping to starve the planet of life-giving oxygen.  (This option is enabled only when viewing a manual page.) A list of printers appears in the cascade menu; this list may be edited in Preferences/Misc.  (Even if only one printer is available, it placed in the cascade menu, rather than being directly available.  This is a feature.) (If the [tn]roff source is not available, TkMan asks if it should try to reverse compile the man page.  If successful, this produces much more appealing output than an ASCII dump.)  By default, incremental searching is not case sensitive, but regular expression searching is; these settings can be toggled with the next two menus.  iff upper means that searching is case sensitive if and only if there is at least one uppercase letter in the search expression--that is, all-lowercase searches are not case sensitive; this idea is taken from Emacs. 

As with xman one may instantiate multiple viewers.  When there is more than one viewer you may choose man pages in one viewer and have their contents shown in another.  Use the Output pulldown (which is labelled with the destination viewer number and which appears and disappears as relevant) to direct one viewer's output destination to another.  With this feature one may easily compare two similar man pages for differences, keep one man page always visible, or examine several man pages from a particular volume listing or a SEE ALSO section.  Output only affects the display destination of man pages. 

TkMan builds at startup an internal database of all manual page names in order to quickly search for a particular name. If you install new manual pages or otherwise change the contents of man page directories after TkMan as been started, invoke Rebuild Database. In order to pick up changes in MANPATH, use the companion script retkman, executed from the same command line as that in which the MANPATH was changed. Rebuild Glimpse Database creates and then maintains the index that is used for full text searches.  The Glimpse database is not updated automatically due to the large amount of time it may take, though often Glimpse can incrementally rebuild the index in just a few minutes.  

When exited via the Quit button, TkMan saves its state.  One may guard against losing highlighting, shortcuts and other would-be persistent information without quitting by invoking Checkpoint state to .tkman; Quit, don't update performs the opposite operation. 

At the bottom right corner of the screen, Mono toggles between the proportionally-spaced font and a monospaced one, for use in those man pages that rely on a fixed-width font to align columns.  Quit exits TkMan, of course, after saving some state information (see below).  To exit without saving status information, select the Quit option from the Occasionals (...) menu. 


Texinfo Reader

A special entry under the Volumes menu calls up a list of GNU Texinfo (aka info) books.  As distinct from other Texinfo readers--info, xinfo, tkinfo, and the one built into Emacs--the reader in TkMan interprets the document source file, which can be compressed, rather than the character-formatted version.  This makes possible significantly higher quality page rendering, which is rendered with Tk's expressive text widget. 

Furthermore, TkMan provides a different interface to Texinfo files. Other readers navigate among "nodes".  At a given point, one may be able to go to the next or previous node in sequence or up to the parent node.  In other words, in navigating the "info-space", you only have immediate context information.  At least for me, this leads to being "lost in info-space".  TkMan's Texinfo reader provides an outliner user interface, which gives much more positional context.  The little number to the right of the section title reports the number of subsections it holds.  I think an outlining interface is well matched to the usually highly hierarchically structured Texinfo files. 

Texinfo books can be very large; Elisp's manual is 18MB for example.  Other info readers show parts of corresponding formatted files that consume approximately the same amount of disk space as their source. In contrast, TkMan processes the source files to extract only the hierachy information and caches this on disk; usually this amounts to about 2% of the source file size, after compression (no cacheing takes place if processing can be done in less than 1.5 seconds).  Moreover, main memory use is minimized by loading in only those sections that have been opened for viewing in the outline.  (Actually, for any opened section, the next section is prefetched and preformatted, so that it is immediately available if you're reading consecutive sections.) 

If some stick-in-the-mud sys admin has not enabled TkMan's Texinfo reader, you can set it up for individual use.  In Preferences/Database set Texinfo index directory to the directory in which to find a file named dir.tkman as well as to store one cache file per Texinfo book (regardless of the number of files that comprise it).  This can be the same directory as present Texinfo directory. The dir.tkman file is a list of Texinfo files just like the dir file used by other info readers, except paths are full paths to each top source file.  I've included my dir.tkman as a pattern.  (Texinfo support  could be extended to handle multiple info directories but I don't think that's necessary now as just have one short index files per info manual regardless of how many constituant files the manual has,  whereas before the info directory was lengthened with many files per book.) The Texinfo volume is shown and reports errors in the file. This file read from disk every time it changes so you can dynamically experiment with it without restarting TkMan.  Texinfo files must be suffixed with .texi or .texinfo to be recognized as such.  In fact, a file need not be found in a dir.tkman list; any file with those suffixes are treated as Texinfo files, whether they are "top level" files that recursively include all the others in the book, or not.  Texinfo source files can be compressed.  If you're the effective sys admin for a shared repository as indicated by a writable Texinfo cache directory that is not in your home directory, you can build all the Texinfo cache files via the menu .../Rebuild Database/Texinfo.  Otherwise, cache files are built on demand and added if have you have write permission to the cache directory. 

Searching uses gzgrep (if you have it) to search the full text on disk, maps hits back into sections, and faults them in.  If there are hits in many different sections, rather than fault in all the sections at considerable cost of time and memory, the first 20 or so sections  that have not already been read in are faulted in.  Repeating the search will bring in the next 20 sections with hits and so on until all sections with hits are displayed.  Searching is done in the Texinfo source and results displayed in the formatted text, which can lean to some discrepencies, as for instance references to the program TeX are specified as @TeX{} in the source but appear as TEX (with lowered "E") in the formatted (in this case search for TeX|TEX; searching for text will find both but will also  find numerous occurances of text). 

Texinfo tags not supported: @image, @kbdinputstyle, @macro, @exdent, hyperlinks across Texinfo documents.  Let me know if any of these is heavily used, and where. Also, nested tables and lists can get confused. 


Version Differences

If you care to put your man pages under RCS revision source control, you can optionally have TkMan display a man page with differences--additions, deletions,  changes--from its previous version. (Differences that are simply a matter of formatting tweaks-- not substantive content revisions--are ignored, assuming diff correctly determines the correspondences between old and new text.) For example, for Tk's text widget you can see that in moving from Tk 4.1 to 8.0, support for embedded images is entirely new and mention of the X selection is stricken from the section THE SELECTION, whereas the canvas widget man page has been augmented to mention that windows are always drawn on top and that canvases can be output to a channel, though the channel option isn't separately listed in the list of options for the postscript command.  This information was discovered through a quick scan through of the respective man pages while looking for large patches of italics, bold-italics, and overstrike text. 

The RCS archive is searched for the newest revision that has differences.  This way when you install new documentation you can check it into RCS right away.  This might not be suitable for documentation that is frequently revised, as that for one's own project perhaps.  For these cases, you can specify the exact RCS branch to diff against by associating the symbolic name checkpoint with that branch (see rcs's -n and -N options).  By following a simple routine, you can maintain version information for a large collection of pages belonging to a piece of software as they are updated from version to version: Before installing new pages, rcs -Ncheckpoint on all related pages to set the point against which to compute differences. After installation, ci -l -t'version X.Y' to record them in the RCS archive. 

Version difference information is cached into tiny, compressed files with one line per change plus those lines deleted from the old version.  Like Texinfo cache files, differences cache files are created on demand as one views files, or can be built/updated all at once with the .../Rebuild Database/Man page version (RCS) caches menu.  Version difference information is cached into a subdirectory called RCSdiff under the place where the corresponding cached manual page would be stored, which is either .../man/catn or, if .../man/catn is not writable, in a separate directory tree specifically for this purpose. 

As well, for manual pages with version information, TkMan dynamically introduces a pseudo-section that displays the version log, with hyperlinks that call up older versions.  These older versions can be highlighted as stored as shortcuts. 

Difference information is given on a line by line basis.  (I tried wdiff for word granularity, but wdiff doesn't correctly associate newlines with old text.)  This means that if you're using the long lines option, difference information is rather coarse, on the paragraph level. 

If you're using this option, don't compress the corresponding man page source as RCS doesn't like this.  You can still compress cached formatted pages regardless. 

If you are taking advantage of both Glimpse and man page versioning, you can prevent glimpse from indexing RCS versioning information by giving each RCS directory a chmod -x RCS. 


Preferences

The Preferences... choice in the Occasionals pulldown menu (called ...) brings up a graphical user interface to setting various attributes of TkMan, including fonts, colors, and icons.  Click on a checkbutton at the top of the window to bring up the corresponding group of choices.  After making a set of choices, the Apply button reconfigures the running application to show these changes, OK sets the changes for use now and in the future, Cancel quits the dialog and sets all choices to their settings as of the time Preferences was called up, and Defaults resets the settings in the current group to those set by TkMan out of the box. I suggest touring all the options to discover what all's available,  tweaking to preference along the way. 

The first line in the Fonts group specifies the font to use for the general user interface-- labels on buttons and text in menus.  The first menu in the line labeled Interface sets the font family, the next menu sets the font size, and the last the font styling (normal, bold, italics, bold-italics). Text display makes these settings for the text box in which the manual page contents are displayed.  For listings of all man pages in a particular volume (as chosen with the Volumes menu), you may wish to use a smaller font so that more names fit on the screen at once.  The text added/changed/deleted choices-- which apply only if you are showing man page version differences as described above--use the same font size as Text display. 

Colors sets the foreground and background colors to use for the the general user interface, the buttons of the user interface, and the  manual page text display box.  In addition it sets the color (or, with editing of the .tkman file, font) in which to show various classes of text in the text box, including manual page references, incremental search hits, regular expression search hits, and highlighted regions. 

The See group specifies what information and controls to display. Usually manual page headers and footers are uninteresting and therefore are stripped out, but a canonical header and footer (along the date the page was installed in the man/mann directory  and by whom) to be shown at the bottom of every page can be requested.   In an effort to maximize screen real estate devoted to displaying content, you can choose to hide all menus and buttons (the row with Sections, Highlights, Volumes at top; and Search, Mono, Quit at bottom) until they made are active, either by tabbing into that line or by moving the mouse into that region. This is for the experienced user who knows where things are. Solaris and IRIX systems come with many "subvolumes"--that is volumes with names like "3x" and "4dm" that form subgroupings under the main volumes "3" and "4", respectively--and you make use tkmandesc commands to add your own subvolumes.  You can reduce the length of the main Volumes menu by placing all volumes in such groups as cascaded menus. When a highlighted passage is jumped to via the Highlights menu, some number of lines of back context are included; the exact number of lines is configurable.   Around the man page display area runs a buffer region of a few pixels, the exact width of  which is configurable. 

You have the option to view manual pages as outlines whereby sections and subsections can be collapsed and expanded.  The choices here control the initial outline displayed when a page is first displayed.  You can have all sections collapsed or all expanded, or turn off outlining altogether. More interestingly, you can have all collapsed but for those that match a pattern.  This defaults to match the sections long Names, short Descriptions, Synopsis, Author, and See Also.  The pattern is matched against the name of the section appended with the number of lines in that section. The number of lines is used to expand sections only if they are long enough to be interesting or short enough to leave screen real estate for other sections. 

It is likely that any text you highlighted on a page is important, and you can elect to show this text even inside otherwise collapsed outline sections. In this way, highlighted text can serve as a combination note and "in-place bookmark":  Sometimes just the excerpted lines containing the highlighted text provides sufficient information; if not, click on the highlight and the section will expand and scroll to that text (with a configurable number of lines of back context). You can turn off this option (never), or just excerpt the highlights when the page is first shown (at first),  after which any action that opens or collapses an outline section dismisses the excerpts. Setting the option to always keeps the corresponding category of text always visible  and uses a plain font as opposed to at first's italics. Likewise for manual page references. Likewise for searches, except that searches first close up all outline sections.  It can be helpful to have some words jump out on the page, as for instance words that indicate danger ("warning", "unsafe"), standards conformance ("internationalization", "POSIX"),  pointers to documentation in different formats ("Texinfo", "PostScript", "HTML"),  or system-specific options in general software ("Solaris", "Macintosh"), to name a few. The regular expression on the Autosearch line are automatically found in the manual page and highlighted to immediately grab the eye, on their first character so as not to overwhelm the screen. In general, the more internal structure, like command line options and subcommands, the greater the value of Notemarks.  A second regexp of less urgent strings is also autosearched, but not reported as Notemarks; you see them when viewing that part of the page. Notemarks are another reason to use the outlining interface, for with text collapsed to more or less fit on one screen, you can actually see them all immediately, rather than scrolling (or not) to see them (or not). 

Sometimes even after opening selected sections and showing highlights, some vertical screen real estate remains.  If so, this space is filled with as much information as fits from the highly important Description section, if that section is not already fully expanded, thus maximizing the information for a page that is shown on its first screen. The Excerpt line lists, in priority order, the sections that should be excerpted, either always in their entirity or as there is room on the first screen. Perl 5 man pages aren't very amenable to outlining or excerpting:  they'll often have a couple line NAME section followed by 1000s of lines in DESCRIPTION--effectively putting what would be tens of printed pages into one section.  On the other hand, environ(5),  expect(1), printf(3), Tcl's file(n), and Tk's text(n), canvas(n) and wm(n) work especially well.   

If a page is short enought to fit on the screen in its entirety, outlining is superfluous and not applied.  Also overriding the initial outline settings, the page always scrolls to show the last screen viewed, expanding sections as necessary. 

If a man page has not been formatted by nroff, TkMan must first pipe the source text through nroff.  By turning on Cache formatted (nroff'ed) pages in the Database group, the nroff-formatted text is saved to disk (if possible), thereby eliminating this time-consuming step the next time the man page is read .   The on & compress setting will compress the page, which saves on disk space (often substantially as much of a formatted page is whitespace), but will make it unavailable to other manual pagers that don't handle compression (you may be forced to use a character-based man pager over a dial-up line or during system debugging after a crash).   If you're using groff as your formatter and you have man page source available (sorry SGI, IBM), you have the option to more effectively use screen space by lengthening lines. (Cached pages of various lengths can co-exist:  A page of length n is stored in a directory named .../man/catvolume@n.) When formatting pages to use longer lines, hyphenation is supressed so that searches in the page aren't frustrated by hyphenated words. If you take your manual page source from CD-ROM or run in a network that makes the corresponding cat directories unwritable, you can set a directory to serve as the root of a parallel hierarchy for cached formatted pages. The default setting, /var/catman, makes the whole process conform to  the Linux FSSTND specification, but you can set it to someplace else, say,  /var/cache/man for the FHS 2.0 spec, or to your home directory.  (FHS 2.0 specifies that pages in .../share/man directories be cached in the exact same path as a page of the same name in .../man.  Obviously this leads to conflicts, so that part of the specification is ignored for the sake of cache integrity.) 

Volumes' (recent) choice will show all manual pages that have been added or changed within the past n days.  If you usually use the GNU implementations of standard UNIX utilities, which usually boast enhanced functionality, you can redirect man page references to the GNU version for those that are named by taking the UNIX name and prepending a g (e.g., od => god). If you have this option switched on but have an exceptional case (for instance you want zip, the free file compressor compatible with PKZIP,  and not gzip (which is a superior replacement for compress) prefix the name with a caret (^, as in "^zip"). 

Glimpse works best when searching for relatively uncommon words; guard against getting too many hits by setting the maximum number reported. By default Glimpse indexes are placed at the root of the corresponding man hierarchy, where they can be shared.  For the case when an individual may not have write permission there, a single, unified index can be created and stored locally (though you lose control of it from Paths settings). Unified indexes are faster than distributed.  On the other hand, rebuilding the index generally takes longer, since the distributed version will only have to rebuild the indexes for those directories that changed.  On the third hand, glimpse can usually incrementally rebuild my unified index in just a couple of minutes. For unified indexes and also for "stray cats" (i.e., directories not part of a set of man hierarchy directories), you should specify an auxiliary directory to hold the index. 

As mentioned above, TkMan displays Texinfo books by reading Texinfo source code.  For better performance, TkMan caches indexes into these books, some of which are very long (18MB for Elisp).  Although indexes are relatively small, 2% or so of the original, they still must be stored somewhere, specified here. 

The Window group sets all the options relating to window management, including iconification. The pathnames of the icon bitmap and icon mask should be the full pathnames (beginning with a `/').  If Path name to icon bitmap is set to (default), the internal icon by Rei Shinozuka will be used.  If your window manager has trouble with iconifying and deiconifying TkMan and you are using the (default) setting, try setting the icon to a path. 

Miscellaneous.  By default, man page links are activated by single clicking.  If it is changed to double with Mouse click to activate hyperlink, the first click puts the name in the entry box so that it can be used as the apropos or glimpse pattern as well as for man searching.  This click once to select, twice to launch follows the Macintosh convention. 

TkMan can extract section headers from all manual pages, but only some manual page macros format subsection headers in a way that can be distinguished from ordinary text; if your macros do, turn this option on to add subsections to the Sections menu. If you find that many lines are being interpreted as subsections, turn it back off. The History pulldown, the down arrow to the right of the name typein box, must balance depth of the list against ease of finding an entry; set your own inflection point with this menu.  Tk deviates from Motif behavior slightly, as for instance in highlighting buttons when they're under the cursor and in the file selection box, but you can observe strict Motif behavior. 


Customizing TkMan

There are four levels of configuration. 

(1) Transparent.  Simply use TkMan and it will remember your window size and placement, short cuts, and highlights (if you quit out of TkMan via the Quit button). 

(2) Preferences editor (see Preferences above). 

(3) Configuration file.  Most interesting settings--those  in the Preferences dialogs and more not available there--can be changed by editing one's own ~/.tkman file.  Thus, a single copy of TkMan (i.e., the executable tkman) can be shared, but each user can have his own customized setup.  (The file ~/.tkman is created/rewritten every time one quits TkMan via the Quit button in the lower right corner.  Therefore, to get a ~/.tkman to edit, first run and quit TkMan.  Do not create one from scratch as it will not have the proper format used for saving other persistent information, and your work will be overwritten, which is to say lost.  As well, be careful not to edit a ~/.tkman file only to have it overwritten when a currently running TkMan quits.) 

Options that match the defaults are commented out (i.e., preceded by a #).  This is so that any changes in TkMan defaults will propagate nicely to end users, while maintaining a list of all interesting variables. To override the default settings for these options, first comment in the line. 

The ~/.tkman save file is the place to add or delete colors to the default set, which will subsequently become menu choices in Preferences, by editing in place the variable man(colors).  One may also edit the order of Shortcuts in the man(shortcuts) variable. Other interesting variables include man(highlight), which can be edited to change the background in place of the foreground, or both the foreground and background, or a color and the font as with the following setting:
set man(highlight) {bold-italics -background #ffd8ffffb332} 

Arbitrary Tcl commands, including tkmandesc commands (described below), can be appended to ~/.tkman (after the ### your additions go below line). 

To set absolutely the volume names for which all directories should be searched, edit the parallel arrays on these existing lines:
set man(manList) ...
set man(manTitleList) ...
 Changing the order volumes in these lists (make sure to keep the two lists in parallel correspondence) changes the precedence of matches when two or more pages have the same name: the page found in the earlier volume in this list is show first. 

Additional useful commands include wm(n), which deals with the window manager; bind(n), which changes keyboard and mouse bindings not related to the text display window; options, which sets the X defaults; and text(n), which describes the text widget. 

(4) Source code.  Of course, but if you make generally useful changes or have suggestions for some, please report them back to me so I may share the wealth with the next release. 


Environment

MANPATH 
      Colon-separated list of directory paths in which to search for man pages. Usually the final directory in a path is man, as in /usr/man.  This variable is standard across man pagers, including man(1) and xman(1). 

DISPLAY_DPI 
      Usually the screen DPI is calculated automatically and from this the closest  existing font DPI is chosen.  You can override this calculation by setting  DISPLAY_DPI; common values of screen DPI are 75, 90 and 100. 

TKMAN 
      The environment variable named TKMAN, if it exists, is used to set command line options.  Any options specified explicitly (as from a shell or in a script) override the settings in TKMAN. Any settings made with command-line options apply for the current execution only. Many of these options can be set persistently via the Preferences dialog (under the Occasionals menu). 
       


Command line options

-title title 
      Place title in the window's title bar. 

-geometry WxH+X+Y 
      Specify the geometry for this invocation only.  To assign a persistent geometry, start up TkMan, size and place the window as desired, then (this is important) quit via the Quit button in the lower right corner. 

-iconify and -noiconify 
      Start up iconified or uniconified (the default), respectively. 

-iconname name 
      Use name in place of the uniconified window's title for the icon name. 

-iconbitmap bitmap-path and -iconmask bitmap-path 
      Specify the icon bitmap and its mask. 

-iconposition (+|-)x(+|-)y 
      Place the icon at the given position; -iconposition "" "" cancels any such hints to the window manager. 

-dpi value 
      Use value DPI fonts.  Most X servers have 75 and 100 dpi fonts.   On the same monitor, 100 dpi fonts appear larger. 

-debug or -nodebug 
      Generate (or not) debugging information. 

-startup filename 
      Use filename in place of ~/.tkman as the startup file; "" indictates no startup file. 

-quit save and -quit nosave 
      Specify that the startup file (usually ~/.tkman) should be updated (save) or not (nosave) when quitting by the Quit button. 

-v 
      Show the current version of TkMan and exit immediately thereafter. 

-M path-list
 or -M+ path-list
 or -+M path-list 
      As with man, change the search path for manual pages to the given colon-separated list of directory subtrees.  -M+ appends and -+M prepends these directories to the current list. 

--help Display a list of options. 
       


Key bindings

Key bindings related to the text display box are kept in the sb array in ~/.tkman (for more information on Tcl's arrays, refer to the array(n) man page.  In editing the sb(key,...) keyboard bindings, modifiers MUST be listed in the following order: M (for meta), C (control), A (alt).  DO NOT USE SHIFT.  It is not a general modifier: Some keyboards require shift for different characters, resulting in incompatibilities in bindings.  For instance, set sb(key,M-less) pagestart is a valid binding on keyboards worldwide, whereas set sb(key,MS-less) is not.  For this reason, the status of the shift key is suppressed in matching for bindings.  To make a binding without a modifier key, precede the character by `-', as in set sb(key,-space) pagedown. 


tkmandesc

Like xman, TkMan gives you directory-by-directory control over named volume contents.  Unlike and superior to xman, however, each individual user controls directory-to-volume placement, rather than facing a single specification for each directory tree that must be observed by all. 

By default a matrix is created by taking the product of directories in the MANPATH crossed with volume names, with the yield of each volume containing all the corresponding subdirectories in the MANPATH.  By adding Tcl commands to your ~/.tkman (see above), you may add new volume names and add, move, copy and delete directories to/from/among directories. 

The interface to this functionality takes the form of Tcl commands, so you may need to learn at least pidgin Tcl--particularly the commands that deal with Tcl lists  (including lappend(n), linsert(n), lrange(n), lreplace(n)) and string matching (string(n), match subcommand)--to use this facility to its fullest.  tkmandesc commands are used to handle the nonstandard format of SGI's manual page directories, and the irix_bindings.tcl in the contrib directory is a good source of examples in the use of tkmandesc commands. 

Directory titles and abbreviations are kept in lists.  Abbreviations MUST be unique (capital letters are distinct from lower case), but need not correspond to actual directories.  In fact, volume letters specified here supercede the defaults in identifying a volume in man page searches. 


COMMANDS

The following commands are appended to the file ~/.tkman (see Customizing TkMan, above). 

To recreate a cross product of current section lists:
manDescDefaults
 This cross product is made implicitly before other tkmandesc commands. Almost always this is what one expects.  If it is not, one may suppress the cross product by setting the variable manx(defaults) to a non-null, non-zero value before other tkmandesc commands are invoked. 

To add "pseudo" sections to the current volume name list, at various positions including at end of the list, in alphabetical order, or before or after a specific volume:
manDescAddSects list of (letter, title pairs)
 or manDescAddSects list of (letter, title) pairs sort
 or manDescAddSects list of (letter, title) pairs before sect-letter
 or manDescAddSects list of (letter, title) pairs after sect-letter
 In manual page searches that produce multiple matches, the page found in the earlier volume is the one shown by default. 

To move/copy/delete/add directories:
manDescMove from-list to-list dir-patterns-list
manDescCopy from-list to-list dir-patterns-list
manDescDelete from-list dir-patterns-list
manDescAdd to-list dir-list 

The dir-patterns-list uses the same meta characters as man page searching (see above).  It is matched against MANPATH directories with volume subdirectory appended, as in /usr/man/man3, where /usr/man is a component of the MANPATH and man3 is a volume subdirectory. from-list and to-list are Tcl lists of the unique volume abbreviations (like 1 or 3X); * is an abbreviation for all volumes. 

Adding directories with manDescAdd also makes them available to Glimpse for its indexing. 

Warning: Moving directories from their natural home slightly impairs searching speed when following a reference within a man page.  For instance, say you've moved man pages for X Windows subroutines from their natural home in volume 3 to their own volume called `X'.  Following a reference in XButtonEvent to XAnyEvent(3X11) first searches volume 3; not finding it, TkMan searches all volumes and finally finds it in volume X.  With no hint to look in volume 3 (as given by the 3X11 suffix), the full volume search would have begun straight away.  (Had you clicked in the volume listing for volume X or specified the man page as XButtonEvent.X, volume X would have been searched first, successfully.) 

To help debug tkmandesc scripts, invoke manDescShow to dump to stdout the current correspondence of directories to volumes names. 


EXAMPLES

(1) To collect together all man pages in default volumes 2 and 3 in all directories into a volume called "Programmer Subroutines", add these lines to the tail of ~/.tkman:
manDescAddSects {{p "Programmer Subroutines"}}
manDescMove {2 3} p * 

To place the new section at the same position in the volume pulldown list as volumes 2 and 3:
manDescAddSects {{p "Programmer Subroutines"}} after 2
manDescMove {2 3} p * 

To move only a selected set of directories:
manDescAddSects {{p "Programmer Subroutines"}}
manDescMove * p {/usr/man/man2 /usr/local/man/man3} 

(2) To have a separate volume with all of your and a friend's personal man pages, keeping a duplicate in their default locations:
manDescAddSects {{t "Man Pages de Tom"} {b "Betty Page(s)"}}
manDescCopy *phelps* t *
manDescCopy *page* t * 

(3) To collect the X windows man pages into two sections of their own, one for programmer subroutines and another for the others:
manDescAddSects {{x "X Windows"}} after 1
manDescAddSects {{X "X Subroutines"}} after 3
manDescMove * x *X11*
manDescMove x X *3 

(4) If you never use the programmer subroutines, why not save time and memory by not reading them into the database?
manDescDelete * {*[2348]} (braces prevent Tcl from trying to execute [2348] as a command) 

Alternatively but not equivalently:
manDescDelete {2 3 4 8} * 


tkmandesc vs. xman and SGI

TkMan's tkmandesc capability is patterned after xman's mandesc files.  By placing a mandesc file at the root of a man page directory tree, one may create pseudo volumes and move and copy subdirectories into them.  Silicon Graphics has modified xman so that simply by creating a subdirectory in a regular man subdirectory one creates a new volume.  This is evil.  It violates the individual user's rights to arrange the directory-volume mapping as he pleases, as the mandesc file or subdirectory that spontaneously creates a volume must be observed by all who read that directory.  By contrast, TkMan places the directory-to-volume mapping control in an individual's own ~/.tkman file. This gives the individual complete control and inflicts no pogrom on others who share man page directories.  Therefore, mandesc files are not supported in any way by TkMan. 

One may still share custom setups, however, by sharing the relevant lines of ~/.tkman.  In fact, a tkmandesc version of the standard SGI man page directory setup is included in the contrib directory of the TkMan distribution.  For assistance with SGI-specific directory manipulation, contact Paul Raines (raines@slac.stanford.edu). 


Platform-specific Support

I estimate that fully 75% of my time writing TkMan has been spent not in adding new features but in supporting all the many, gratuitous differences in the various flavors of UNIX.  Amazingly, each is different from every other.  TkMan confronts variations in man page organization, that is, directory structure.  The same percentage holds for PolyglotMan, which deals with variations in the formatting of the pages themselves, things like what character sequence indicates italics and what do page headers and footers look like.  The result of all this work is that you can do a simple installation of TkMan and it will embrace the specifics of your system's manual page installation. 

Here's the classical organization.  The MANPATH environment variable gives a colon-separated list of directory paths, each of which usually but not necessarily ends in a subdirectory named `man'. In each of these directories, the file `whatis' has a line per man page giving its name and a single line description taken from each page's NAME section.  Subdirectories named man[1-9oln] hold the [tn]roff source, and corresponding subdirectories named cat[1-9oln] cache formatted pages.  Within subdirectories, each page given as name.section-number, for example "ls.1".  The page source should always be available; formatted versions are purely optional, and strictly used as a performance enhancement, saving formatting time at runtime.  (Pages that exist in formatted versions only are known as "stray cats".)  Man pages may be compressed, with the type of compression given by a suffix on the file.  Compression can be particularly successful on formatted pages, which contain long strings of spaces. 

Here are all the ways that I can recall that various flavors of UNIX have "improved" the classical organization.  Clearly TkMan can do all that it does without reliance on any extension beyond the classical organization, so how important were these "extensions"? 

SunOS 
   + Just great! 

Solaris 
   + Renaming of `whatis' to `windex', which has an extra field 
   + Nonstandard directory names, e.g., `man1s'. 


Ultrix 
   + Just great (nonstandard tabs in formatted man pages handled by PolyglotMan). 

OSF/1 aka Digital UNIX 
   + Just great ("missing" headers and footers in formatted pages handled by PolyglotMan). 

HP/UX 
   + Compressed page files listed without .Z, which is on its enclosing directory 
   + Concatenates all whatis information into /usr/lib/whatis  

SCO 
   + /etc/default/man configuration file*. 

FreeBSD 

Linux 
   + /etc/man.config or /etc/manpath.config, depending on Linux flavor, configuration file* 
   + FSSTND 

BSDI 
   + Concatenation of all `whatis' files into a single /usr/share/man/whatis.db 
   + Formatted pages given suffix .0 
   + /etc/man.conf configuration file* 

IBM AIX 
   + Have to convert help files from opaque InfoExplorer format to standard /usr/man format. 
   + Have to prevent man pages from being parsed, since they are just simple ASCII files,  only vaguely resembling man pages 

SGI Irix - absolute worst by far 
   + Only pre-formatted pages in /usr/catman 
   + Consequently, doesn't have [tn]roff (what about formatting pages for new software?) 
   + Man sub-subdirectories magically appear as own volumes, with names hidden in their hacked version of xman 
   + Stray cats by default (installs formatted pages only) 
   + Page files named without section but with .z 

* TkMan used to have a variety of ways to set the MANPATH if it was not already set.  The MANPATH is simple to set, is recognized on all flavors of UNIX and all man-related tools, is easily customized, and does everything that these other ways did.  It is now the one and only way to communicate man directories to TkMan. 

For history buffs, here are how a MANPATH would be set if it didn't come from the environment: gmanpath's compiled-in MANPATH, system-specific configuration files (BSDI's /etc/man.conf, Linux's /etc/man.config or /etc/manpath.config, SCO's /etc/default/man), SGI's default /usr/share/catman:/usr/share/man:usr/catman:/usr/man, local default set TkMan's Makefile, calculation from PATH (e.g., /usr/bin:/usr/X11/bin => /usr/man:/usr/X11/man).  (Seriously!) 

What's wrong with configuration files?  BSDI, SCO, and Linux have central configuration files.  One problem is that they're all different from one another and not used by other platforms--and at least some of them are constantly changing.  So general man page-related programs don't know about them, and for TkMan they degenerate into yet another special case.  Not only are these configuration files not portable, they are useless at best or even harmful.  They are useless for a user of any sophistication as he will set MANPATH and PATH to achieve custom control, as opposed the general one-size-fits-all, centrally dictated approach of configuration files.  They are harmful for novice users who will want to customize the MANPATH, as there is now a different way to set it, whereas just following the pattern in a MANPATH setting is straightforward.  Even for novices who wish to remain happily ignorant, system-specific configuration files aren't helpful, because the same effect can be achieved with the universally accepted MANPATH, which can be easily set alongside all the other setup information typically provided for new users.  (Some system-specific configuration files also provided information for deriving a PATH, for which, by the same argument, should be set directly.) 


Multiple Simultaneous OSes

There are several ways to examine the pages from multiple operating systems at the same time.  
   + The simplest is to start up a copy of TkMan in a window running that OS (i.e., on that machine), using the -startup option to give each copy a different ~/.tkman startup file.  Each copy can be given an distinguishing window and icon titles. 
   + If man pages for all systems are available through the file systems mounted on a single machine, you can give a master MANPATH that includes everything.  When a page by that name exists on multiple OSes, a menu labeled ALSO will appear to give access to each one.  Pages can be distinguished in ALSO by their full path names, and when viewed by the full path posted at the top of the window.  You can use the Paths menu under the man menu to focus on just those OSes of interest at the moment. 
   + You can use aliases or short shell scripts to interface to retkman (see below) to restart TkMan with the appropriate MANPATH for whatever OS.  Or you can hack a new menu into TkMan's interface with code in your individual ~/.tkman that lists the available OSes and likewise runs retkman.  


retkman

If you change your MANPATH, either manually or as a side effect of some program, say, a modules system, you can rerun TkMan to pick up the new paths by quitting it and restarting.  The script retkman provides a command that can be used as part of an alias to automatically rerun TkMan as necessary.  If there are multiple instances of TkMan running on different machines, the one restarted is the one on the same machine from which retkman was invoked. 


PolyglotMan

TkMan uses PolyglotMan (formerly known as RosettaMan)  to translate and reformat man pages (see man(5)). PolyglotMan, called rman in its executable form,  takes man pages from most of the popular flavors of UNIX and transforms them into any of a number of text source formats.  Since its inception PolyglotMan accepted formatted pages, and now with version 3.0 interprets [tn]roff source for superior translations. PolyglotMan accepts man pages from SunOS, Sun Solaris, Hewlett-Packard HP-UX, AT&T System V, OSF/1 aka Digital UNIX, DEC Ultrix, SGI IRIX, Linux, FreeBSD, SCO.  It can produce ASCII-only, section headers-only, TkMan, [tn]roff (source), Ensemble, SGML, HTML, MIME, LaTeX, LaTeX2e, RTF, Perl 5 POD.   A modular architecture permits easy addition of additional output formats.  The latest version of PolyglotMan is available from  ftp://ftp.cs.berkeley.edu/ucb/people/phelps/tcltk/rman.tar.Z. 


Other Man and Info Viewers

Among man pagers, as far as I know only TkMan has integrated full text search, highlighting, outlining interface and Notemarks, man page versioning display, comprehensive volume listings including lists of recent pages and results of previous full text search, regular expression and fuzzy page name matching, document map, Preferences configuration panel, and is as widely portable, among other features.  In other areas, such as adding hyperlinks, TkMan isn't unique, but it still probably does things better as a result of continually being refined since 1993 with the valuable suggestions and bug reports from thousands of users  (the builtin Statistics and Information page lists some).  Plus, TkMan has the coolest icon.  And it's heaps more fun. 

Below the term Texinfo refers to the source code for GNU documentation, and info to formatted Texinfo (which is compiled to a form suitable for display on a character terminal, or tty).  As far as I know, only TkMan displays from Texinfo source, making possible its considerably higher quality formatting. 

Of the seemingly innumerable man page and info viewers, here are a few of the more interesting ones I have seen: 

xman - man pages 
      Before I wrote TkMan I used xman, and in fact it was xman's lack of hyperlinks that motivated TkMan. Why use it instead? It comes bundled with X Windows (though perhaps not any more), so it's often already installed. 

Emacs' Superman - man pages 
       Why use it instead? It runs on tty's, it's GPL'ed (for those who have that fetish), and agoraphobics who live inside of Emacs won't have to leave the house. 

KDE Help - man pages and GNU info 
      Based on the KDE HTML viewer, the man pager simply calls man(1) and converts roff output to internal format. It converts man page references to hyperlinks.  It won't convert correctly on all systems outside of Linux, and it doesn't remove page headers and footers.  Its Texinfo viewer is based on compiled info, so the formatting is limited to fixed-width fonts.  Why use it instead? Agoraphobics can run an HTML browser within the same system, though it falls short of Netscape. with a uniform look. --> 

tkinfo - GNU info 
      Why use it instead? Smaller and so may be more appropriate for a system's add-on help viewer, installation's a snap, runs on Macintosh  and Microsoft Windows (though who uses Texinfo there?), widely recommended.  

Refer to http://math-www.uni-paderborn.de/~axel/tkinfo/ for a description of many more Texinfo viewers. 


Author

Copyright (C) 1994-2003  Thomas A. Phelps 
initial prototype developed in 1993 at the
 University of California, Berkeley
 Computer Science Division 


More Information

 My article "TkMan: A Man Born Again" appears in the now defunct X Resource, issue 10, pages 33--46.  Here are the section titles: Introduction, Availability, The User Interface, Navigating among Man Pages, Inspecting Individual Man Pages, Customization, Logical Volumes with tkmandesc, Persistency, The RosettaMan Filter, Extensions, Problems, Future Work, Acknowledgements, Bibliography. 

Two Years with TkMan, a retrospective paper that uses TkMan as an example for various techniques for writing faster and more robust Tcl/Tk programs, was named Best Paper of the 1995 Tcl/Tk Workshop. A Berkeley Computer Science Division technical report (CSD-94-802) is a version of the X Resource article before it was butchered by the editor.

Help page last revised on $Date: 1999/08/24 23:12:29 $
}
foreach qq {{h1 1.0 1.38} {tt 10.45 10.73} {sc 12.262 12.269} {tt 12.393 12.401} {tt 12.439 12.444} {tt 12.537 12.551} {h1 15.0 15.8} {sc 17.0 17.741} {h1 20.0 20.12} {i 23.15 23.31} {manref 25.40 25.43} {manref 25.48 25.52} {manref 25.458 25.465} {sc 27.534 27.536} {tt 29.432 29.442} {diffa 34.86 34.106} {diffd 34.108 34.131} {diffc 34.133 34.156} {tt 45.17 45.24} {sc 45.80 45.87} {h1 50.0 50.11} {i 52.26 52.31} {i 52.119 52.124} {h2 55.0 55.19} {tt 57.139 57.145} {tt 57.159 57.162} {tt 57.233 57.234} {i 57.234 57.235} {tt 57.239 57.240} {i 57.240 57.241} {tt 57.241 57.242} {i 57.250 57.251} {tt 57.346 57.352} {tt 57.646 57.647} {tt 57.679 57.680} {tt 57.745 57.746} {tt 57.750 57.751} {manref 57.809 57.817} {manref 57.855 57.865} {manref 57.1030 57.1036} {manref 57.1082 57.1086} {tt 57.1299 57.1302} {tt 57.1321 57.1324} {i 57.1325 57.1332} {i 57.1333 57.1337} {tt 57.1506 57.1507} {tt 57.1583 57.1591} {tt 57.1641 57.1644} {i 59.336 59.398} {sc 61.71 61.78} {tt 61.197 61.200} {tt 61.202 61.205} {tt 61.207 61.210} {tt 61.214 61.218} {sc 61.284 61.291} {tt 61.345 61.351} {manref 61.368 61.371} {tt 61.420 61.424} {tt 61.454 61.464} {tt 61.509 61.536} {sc 61.627 61.634} {tt 61.800 61.803} {tt 63.0 63.7} {tt 63.96 63.99} {tt 63.128 63.135} {tt 63.151 63.158} {tt 63.176 63.180} {tt 63.185 63.189} {tt 63.304 63.320} {tt 63.428 63.429} {i 63.679 63.682} {tt 65.40 65.43} {tt 65.62 65.71} {tt 65.87 65.94} {tt 65.96 65.111} {tt 65.204 65.211} {tt 65.214 65.216} {i 65.686 65.689} {i 65.731 65.734} {tt 65.798 65.805} {tt 65.823 65.834} {tt 65.836 65.842} {tt 65.847 65.850} {tt 65.921 65.928} {tt 65.1065 65.1077} {tt 65.1095 65.1103} {i 65.1177 65.1181} {i 65.1245 65.1249} {tt 65.1286 65.1294} {tt 65.1318 65.1321} {tt 65.1354 65.1357} {tt 65.1365 65.1367} {tt 65.1400 65.1403} {tt 65.1502 65.1521} {manref 65.1536 65.1543} {i 65.1618 65.1624} {tt 65.1879 65.1886} {tt 67.4 67.9} {tt 67.28 67.31} {tt 67.75 67.78} {sc 67.176 67.183} {sc 67.520 67.527} {tt 67.561 67.568} {tt 69.489 69.496} {tt 69.501 69.508} {tt 69.543 69.565} {tt 69.808 69.811} {tt 71.283 71.284} {tt 71.285 71.286} {tt 71.287 71.288} {tt 71.448 71.449} {tt 71.467 71.468} {tt 73.55 73.60} {tt 73.268 73.269} {tt 73.277 73.287} {tt 73.333 73.334} {tt 73.358 73.375} {tt 73.381 73.407} {tt 73.442 73.443} {tt 73.643 73.644} {tt 73.646 73.648} {tt 73.650 73.651} {tt 73.656 73.657} {tt 73.772 73.778} {tt 73.895 73.899} {h2 76.0 76.25} {i 78.447 78.455} {tt 78.772 78.775} {manref 78.953 78.959} {i 78.999 78.1007} {tt 78.1013 78.1021} {sc 80.298 80.306} {tt 82.212 82.214} {tt 82.383 82.385} {tt 82.399 82.400} {tt 82.547 82.549} {tt 82.563 82.564} {tt 82.751 82.752} {tt 84.509 84.547} {tt 86.1536 86.1541} {tt 88.126 88.131} {tt 88.136 88.139} {tt 88.162 88.165} {tt 88.176 88.182} {tt 88.256 88.258} {tt 88.291 88.294} {tt 88.299 88.302} {tt 88.346 88.349} {tt 88.354 88.357} {tt 88.410 88.413} {tt 88.434 88.437} {tt 88.665 88.672} {tt 88.743 88.746} {tt 88.820 88.823} {tt 90.0 90.3} {tt 90.214 90.217} {tt 90.317 90.320} {tt 90.361 90.364} {tt 90.379 90.382} {tt 90.407 90.413} {tt 90.417 90.420} {tt 90.564 90.567} {manref 94.83 94.89} {tt 94.124 94.130} {tt 94.434 94.437} {tt 94.497 94.500} {tt 98.4 98.7} {tt 98.129 98.138} {h2 101.0 101.14} {tt 103.30 103.33} {tt 103.126 103.130} {tt 103.211 103.221} {tt 103.479 103.495} {tt 103.636 103.644} {sc 103.796 103.801} {tt 103.960 103.969} {tt 105.8 105.12} {sc 105.529 105.537} {tt 107.245 107.261} {sc 107.294 107.301} {tt 107.328 107.335} {sc 107.394 107.401} {tt 107.415 107.439} {tt 109.20 109.24} {tt 109.181 109.207} {tt 109.209 109.227} {tt 111.42 111.46} {tt 111.194 111.198} {tt 111.327 111.331} {tt 111.361 111.364} {h2 114.0 114.14} {i 116.58 116.69} {i 116.75 116.79} {manref 116.129 116.133} {manref 116.135 116.140} {manref 116.142 116.148} {tt 116.150 116.196} {tt 122.117 122.137} {tt 122.142 122.165} {tt 122.213 122.222} {tt 122.395 122.404} {tt 122.451 122.454} {i 122.505 122.509} {i 122.528 122.534} {tt 122.559 122.568} {tt 122.1092 122.1097} {tt 122.1101 122.1109} {tt 122.1176 122.1185} {tt 122.1589 122.1617} {manref 124.15 124.21} {i 124.277 124.311} {tt 124.636 124.642} {tt 124.671 124.674} {tt 124.736 124.743} {tt 124.759 124.763} {tt 124.822 124.826} {tt 126.28 126.34} {tt 126.36 126.50} {tt 126.52 126.58} {tt 126.60 126.67} {h2 129.0 129.19} {diffa 131.136 131.145} {diffd 131.147 131.156} {diffc 131.159 131.166} {tt 131.313 131.317} {sc 131.571 131.584} {tt 131.815 131.825} {diffa 131.960 131.967} {diffc 131.969 131.981} {diffd 131.987 131.997} {i 133.374 133.384} {manref 133.407 133.410} {tt 133.413 133.415} {tt 133.420 133.422} {b 133.612 133.618} {tt 133.641 133.657} {b 133.734 133.739} {tt 133.754 133.775} {tt 135.279 135.329} {tt 135.405 135.412} {tt 135.508 135.516} {i 135.516 135.517} {tt 135.528 135.536} {i 135.536 135.537} {manref 139.67 139.72} {tt 139.99 139.104} {tt 143.85 143.92} {tt 143.165 143.177} {h2 146.0 146.11} {tt 148.4 148.18} {tt 148.67 148.70} {tt 148.318 148.323} {tt 148.391 148.393} {tt 148.442 148.448} {tt 148.551 148.559} {b 150.22 150.27} {tt 150.166 150.175} {tt 150.301 150.313} {tt 150.724 150.736} {b 152.0 152.6} {tt 152.222 152.228} {b 154.4 154.7} {tt 154.236 154.243} {i 154.243 154.244} {b 156.44 156.51} {tt 156.326 156.343} {i 156.533 156.582} {tt 158.509 158.514} {tt 158.578 158.586} {tt 158.702 158.708} {tt 158.802 158.810} {tt 158.1325 158.1335} {tt 160.351 160.358} {sc 160.602 160.606} {sc 160.645 160.656} {manref 160.752 160.762} {manref 160.765 160.774} {manref 160.776 160.785} {manref 160.793 160.800} {manref 160.811 160.818} {manref 160.820 160.829} {manref 160.834 160.839} {tt 164.40 164.45} {tt 164.93 164.98} {tt 164.115 164.147} {b 164.155 164.163} {tt 164.175 164.180} {tt 164.316 164.329} {manref 164.670 164.675} {i 164.895 164.896} {tt 164.928 164.939} {i 164.939 164.945} {tt 164.945 164.946} {i 164.946 164.947} {tt 164.1329 164.1340} {tt 164.1454 164.1468} {tt 166.9 166.17} {i 166.100 166.101} {i 166.346 166.347} {i 166.355 166.357} {i 166.361 166.364} {tt 166.455 166.458} {tt 166.517 166.521} {tt 166.559 166.567} {b 172.4 172.10} {tt 172.198 172.222} {tt 172.233 172.242} {tt 172.390 172.399} {b 174.0 174.4} {tt 174.110 174.143} {i 176.97 176.100} {tt 176.236 176.244} {h1 179.0 179.17} {tt 183.149 183.153} {tt 187.152 187.160} {tt 187.219 187.224} {tt 187.301 187.309} {tt 187.366 187.370} {tt 187.426 187.434} {tt 187.678 187.686} {tt 189.71 189.72} {tt 191.4 191.12} {b 191.143 191.159} {tt 191.173 191.184} {tt 191.235 191.249} {tt 191.296 191.310} {i 191.408 191.411} {i 191.435 191.438} {tt 192.0 192.59} {tt 194.91 194.99} {tt 194.111 194.138} {b 196.81 196.85} {b 196.115 196.123} {tt 197.0 197.20} {tt 198.0 198.25} {manref 201.35 201.40} {manref 201.79 201.86} {manref 201.170 201.177} {manref 201.210 201.217} {h2 206.0 206.11} {tt 209.121 209.124} {tt 209.132 209.140} {manref 209.198 209.204} {manref 209.209 209.216} {sc 212.25 212.28} {sc 212.98 212.101} {sc 212.160 212.171} {sc 212.197 212.200} {sc 215.37 215.42} {sc 215.187 215.192} {tt 215.360 215.371} {h2 219.0 219.20} {tt 221.0 221.7} {i 221.7 221.12} {tt 222.12 222.12} {i 222.12 222.17} {tt 224.0 224.10} {i 224.10 224.17} {tt 225.179 225.183} {tt 227.0 227.8} {tt 227.13 227.23} {tt 230.0 230.10} {i 230.10 230.14} {tt 231.10 231.10} {i 231.10 231.14} {tt 233.0 233.12} {i 233.12 233.23} {tt 233.28 233.38} {i 233.38 233.49} {tt 236.0 236.26} {tt 237.44 237.63} {tt 239.0 239.5} {i 239.5 239.10} {i 240.10 240.15} {sc 240.16 240.19} {tt 242.0 242.6} {tt 242.10 242.18} {tt 245.0 245.9} {i 245.9 245.17} {tt 246.10 246.10} {i 246.10 246.18} {tt 246.31 246.39} {tt 248.0 248.10} {tt 248.15 248.27} {tt 249.45 249.53} {tt 249.74 249.78} {tt 249.88 249.94} {tt 249.117 249.121} {tt 251.0 251.2} {tt 254.0 254.3} {i 254.3 254.12} {tt 255.4 255.8} {i 255.8 255.17} {tt 256.4 256.8} {i 256.8 256.17} {tt 257.14 257.17} {tt 257.117 257.120} {tt 257.133 257.136} {tt 259.0 259.6} {h2 263.0 263.12} {tt 265.61 265.63} {tt 265.73 265.81} {manref 265.134 265.142} {tt 265.169 265.180} {tt 265.249 265.250} {tt 265.263 265.264} {tt 265.276 265.277} {tt 265.449 265.477} {tt 265.529 265.548} {tt 265.722 265.749} {h2 268.0 268.9} {tt 270.5 270.9} {tt 270.110 270.114} {sc 272.75 272.82} {sc 272.195 272.202} {tt 272.236 272.244} {manref 274.177 274.187} {manref 274.189 274.199} {manref 274.201 274.210} {manref 274.212 274.223} {manref 274.246 274.255} {tt 274.257 274.262} {tt 274.417 274.434} {tt 274.442 274.449} {h3 279.0 279.8} {b 281.27 281.35} {tt 281.48 281.56} {tt 284.0 284.15} {tt 285.186 285.200} {tt 288.0 288.16} {i 288.16 288.45} {tt 289.4 289.20} {i 289.20 289.49} {tt 290.4 290.20} {i 290.20 290.49} {i 290.57 290.68} {tt 291.4 291.20} {i 291.20 291.49} {i 291.56 291.67} {tt 295.0 295.12} {i 295.12 295.21} {i 295.22 295.29} {i 295.30 295.47} {tt 296.0 296.12} {i 296.12 296.21} {i 296.22 296.29} {i 296.30 296.47} {tt 297.0 297.14} {i 297.14 297.23} {i 297.24 297.41} {tt 298.0 298.11} {i 298.11 298.18} {i 298.19 298.27} {i 300.4 300.21} {sc 300.110 300.117} {tt 300.171 300.184} {tt 300.192 300.200} {sc 300.223 300.230} {tt 300.235 300.239} {i 300.266 300.275} {i 300.280 300.287} {tt 300.343 300.344} {tt 300.348 300.350} {tt 300.353 300.354} {tt 302.24 302.34} {tt 304.293 304.305} {tt 304.309 304.324} {tt 304.478 304.482} {tt 304.629 304.643} {tt 306.40 306.51} {h3 309.0 309.8} {tt 311.162 311.170} {tt 312.0 312.46} {tt 313.0 313.21} {tt 316.0 316.54} {tt 317.0 317.21} {tt 320.0 320.46} {tt 321.0 321.51} {tt 324.0 324.60} {tt 325.0 325.24} {tt 326.0 326.22} {tt 329.0 329.41} {tt 330.0 330.45} {tt 331.0 331.21} {tt 332.0 332.18} {tt 335.0 335.25} {tt 335.69 335.75} {tt 338.0 338.25} {h3 341.0 341.26} {tt 343.48 343.52} {tt 343.244 343.248} {tt 343.670 343.678} {tt 345.77 345.85} {tt 345.181 345.188} {tt 345.305 345.329} {h1 348.0 348.25} {i 350.215 350.220} {sc 352.40 352.47} {sc 352.337 352.341} {i 352.528 352.532} {i 352.533 352.547} {tt 362.86 362.92} {tt 372.46 372.61} {tt 375.5 375.21} {tt 380.5 380.20} {tt 380.24 380.43} {tt 385.34 385.36} {tt 386.5 386.18} {tt 393.33 393.44} {i 396.16 396.26} {sc 399.50 399.57} {sc 399.90 399.97} {tt 401.95 401.103} {sc 401.118 401.125} {tt 401.353 401.361} {sc 401.380 401.384} {sc 403.523 403.530} {sc 403.535 403.539} {sc 403.727 403.734} {sc 403.819 403.826} {sc 403.1032 403.1039} {sc 403.1225 403.1229} {h2 406.0 406.26} {sc 410.124 410.131} {sc 410.224 410.228} {sc 410.300 410.304} {tt 410.414 410.419} {tt 410.435 410.438} {tt 411.64 411.71} {sc 411.122 411.129} {tt 411.284 411.291} {h1 414.0 414.7} {sc 416.19 416.26} {tt 416.192 416.199} {tt 416.432 416.439} {h1 419.0 419.11} {i 421.11 421.22} {manref 421.96 421.102} {i 421.105 421.116} {manref 421.125 421.129} {i 421.415 421.426} {tt 421.843 421.903} {h1 424.0 424.26} {tt 426.647 426.673} {i 428.15 428.22} {i 428.76 428.80} {i 428.180 428.183} {i 433.107 433.126} {i 436.7 436.26} {manref 439.63 439.69} {i 439.370 439.389} {i 442.6 442.25} {tt 444.9 444.55} {h1 447.0 447.6} {h1 455.0 455.16} {i 457.65 457.75} {i 459.0 459.20} {i 459.286 459.296} {tt 459.402 459.438} } {
	eval $t tag add $qq
}

foreach qq {{abstract 15.0} {introduction1 20.0} {using1 50.0} {locating2 55.0} {working2 76.0} {other2 101.0} {texinfo2 114.0} {version2 129.0} {preferences2 146.0} {customizing1 179.0} {environment2 206.0} {command2 219.0} {key2 263.0} {tkmandesc2 268.0} {platspec1 348.0} {multios2 406.0} {retkman1 414.0} {polyglotman1 419.0} {other1 424.0} {author1 447.0} {more1 455.0} } {
	eval $t mark set $qq
}

}
image create bitmap icon -foreground black -background white -data {
#define tkman_width 64
#define tkman_height 64
static char tkman_bits[] = {
   0x33, 0x33, 0x23, 0x00, 0x0e, 0xc6, 0xfc, 0xff, 0x33, 0xb3, 0xe1, 0x00,
   0x06, 0x83, 0xfc, 0xff, 0xcc, 0xfc, 0xc0, 0x01, 0x80, 0x81, 0x77, 0x77,
   0xcc, 0xff, 0x00, 0x03, 0xc0, 0x80, 0xff, 0xff, 0xff, 0xdf, 0x00, 0x0e,
   0x60, 0xc0, 0xff, 0xff, 0xff, 0xc1, 0x00, 0x18, 0x38, 0xc0, 0xfc, 0xff,
   0x0f, 0xc0, 0x01, 0xf0, 0x0f, 0xc0, 0x76, 0x77, 0x00, 0x80, 0x01, 0xe0,
   0x07, 0x60, 0xfe, 0xdf, 0x00, 0x98, 0x03, 0xc0, 0x03, 0x70, 0xfc, 0x0f,
   0x00, 0x88, 0x03, 0xe0, 0x07, 0x30, 0xff, 0x07, 0x00, 0x04, 0x07, 0x70,
   0x0f, 0x18, 0x77, 0x03, 0x00, 0x04, 0x0f, 0xf8, 0x1f, 0xcc, 0xff, 0x03,
   0x00, 0x02, 0x0e, 0xfc, 0x3f, 0xe4, 0xff, 0x01, 0x00, 0x0a, 0x1c, 0xf6,
   0xff, 0xff, 0xff, 0x01, 0x00, 0x07, 0x38, 0x73, 0x77, 0x77, 0xf7, 0x00,
   0x00, 0x83, 0xf0, 0xe9, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x43, 0xe0, 0x00,
   0xff, 0xff, 0x1f, 0x00, 0x80, 0x31, 0x30, 0x22, 0xfe, 0xff, 0x1f, 0x00,
   0x00, 0x78, 0x18, 0x00, 0x74, 0x77, 0x07, 0x00, 0x00, 0x1c, 0x8c, 0x88,
   0xf8, 0xff, 0x03, 0x00, 0x00, 0x06, 0x06, 0x00, 0xc0, 0xdd, 0x07, 0x00,
   0x00, 0x00, 0x23, 0x22, 0x22, 0x22, 0x0f, 0x00, 0x00, 0x80, 0x99, 0x99,
   0x99, 0x99, 0x1d, 0x3c, 0x78, 0xc0, 0x99, 0x99, 0x99, 0x99, 0xf9, 0xff,
   0xff, 0x63, 0x66, 0x66, 0x66, 0x66, 0xf6, 0x83, 0x87, 0x7f, 0x66, 0x66,
   0x66, 0x66, 0xe6, 0x00, 0x01, 0x9c, 0x99, 0x99, 0x99, 0x99, 0xd9, 0x3f,
   0xe0, 0x9f, 0x99, 0x99, 0x99, 0x99, 0xf9, 0x1f, 0xc0, 0x7f, 0x00, 0x00,
   0x00, 0x00, 0x0c, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x8f, 0x07, 0x00,
   0x00, 0x80, 0xff, 0xff, 0xf7, 0x87, 0x07, 0x00, 0x00, 0x80, 0xff, 0xff,
   0xf7, 0xa7, 0x0f, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xf7, 0x87, 0xff, 0x03,
   0x00, 0xfc, 0xff, 0xff, 0xff, 0x8b, 0xff, 0x01, 0x00, 0xc0, 0x9f, 0xcf,
   0xe7, 0x83, 0x0f, 0x00, 0x00, 0x80, 0xbf, 0xef, 0xe7, 0xe3, 0x0f, 0x00,
   0x00, 0xc0, 0x80, 0x0f, 0xe0, 0xe3, 0x0f, 0x00, 0x00, 0xfe, 0x88, 0x8f,
   0xe8, 0xfb, 0xf3, 0x07, 0x00, 0x7c, 0x80, 0x0f, 0xe0, 0xfb, 0xe1, 0x03,
   0x00, 0x60, 0xa2, 0x2f, 0xe2, 0xff, 0x20, 0x00, 0x00, 0x20, 0x80, 0x0f,
   0xe0, 0xff, 0x28, 0x00, 0x00, 0x9f, 0x88, 0x8f, 0xe8, 0xff, 0xe0, 0x07,
   0x00, 0x1e, 0x80, 0x0f, 0xe0, 0xff, 0xc1, 0x03, 0x00, 0x38, 0xa2, 0x2f,
   0xe2, 0xfb, 0xc3, 0x00, 0x01, 0x78, 0x80, 0x0f, 0xe0, 0xf3, 0xc7, 0x01,
   0xff, 0x9f, 0x88, 0x8f, 0xe8, 0xeb, 0x8f, 0xff, 0xff, 0x9f, 0x81, 0x0f,
   0xe0, 0xc3, 0x9f, 0xff, 0x00, 0x63, 0xa2, 0x2f, 0xe2, 0xa3, 0x7f, 0x7e,
   0x00, 0x67, 0x86, 0x0f, 0xe0, 0x03, 0x7f, 0x3e, 0x00, 0x9e, 0xc9, 0x9f,
   0xf8, 0x8f, 0x9f, 0x1d, 0x10, 0x9c, 0xd9, 0x1f, 0xf0, 0x87, 0x9f, 0x0f,
   0x30, 0x78, 0xe6, 0x3f, 0xf2, 0xa7, 0x67, 0x06, 0x30, 0x30, 0xe6, 0x1f,
   0xf0, 0x87, 0x67, 0x03, 0x70, 0x60, 0x99, 0x80, 0x08, 0x08, 0xd9, 0x11,
   0xf0, 0xc0, 0x98, 0x01, 0x00, 0x80, 0xd9, 0x00, 0xd0, 0x80, 0x65, 0x22,
   0x22, 0x42, 0x66, 0x08, 0xd0, 0x01, 0x63, 0x06, 0x00, 0x60, 0x36, 0x04,
   0x80, 0x03, 0x97, 0x89, 0x88, 0x90, 0x19, 0x06, 0x80, 0x03, 0x8e, 0x19,
   0x00, 0x98, 0x0d, 0x07, 0x00, 0x04, 0x5c, 0x26, 0x22, 0x66, 0x06, 0x03,
   0x00, 0x00, 0x18, 0x66, 0x00, 0x66, 0x83, 0x02, 0x00, 0x00, 0x30, 0x99,
   0x08, 0x99, 0x21, 0x01, 0x00, 0x00, 0x60, 0x98, 0x81, 0xd9, 0x00, 0x01,
   0x00, 0x00, 0xc0, 0x64, 0x62, 0x66, 0x00, 0x00};
}
image create bitmap face -foreground black -background white -data {
#define idbw48ed_width 48
#define idbw48ed_height 48
static char idbw48ed_bits[] = {
 0xf0,0xff,0xff,0xff,0xff,0xff,0xfc,0xff,0xff,0xff,0xff,0xff,0xf8,0xff,0xff,
 0xff,0xff,0xff,0xfc,0xff,0xff,0xff,0xff,0xff,0xfa,0x3f,0xc5,0xff,0xff,0xff,
 0xf8,0x3f,0x01,0xff,0xff,0xff,0xfc,0x5f,0x02,0xfe,0xff,0xff,0xfd,0x5f,0x00,
 0xf8,0xff,0xff,0xfc,0x3f,0x01,0xf0,0xff,0xff,0xf8,0x2f,0x04,0xe0,0xff,0xff,
 0xfd,0xff,0x01,0x01,0xff,0xff,0xfc,0xff,0x0b,0x00,0xf8,0xff,0xfc,0xff,0x0f,
 0xf4,0xfb,0xff,0xfa,0x1f,0x76,0xfc,0xef,0xff,0xfc,0xef,0x3d,0xfd,0xbf,0xff,
 0xff,0xff,0x56,0x54,0xb8,0xff,0xfc,0xff,0x3f,0xf7,0x95,0xff,0xfd,0xff,0x74,
 0xed,0xb5,0xff,0xfd,0x2f,0x5d,0xfb,0x37,0xff,0xfa,0x5b,0x7c,0x47,0x7f,0xff,
 0xfc,0x1a,0xdd,0x2b,0x98,0xff,0xfa,0x23,0xbe,0x82,0x52,0xff,0xec,0x05,0x9b,
 0x05,0xf4,0xff,0xf0,0x81,0x8e,0x07,0xd0,0xff,0xe8,0x86,0x07,0x0b,0x40,0xbf,
 0xf4,0x41,0x8f,0x0f,0xe0,0xce,0xf8,0xa5,0x5f,0x0b,0xa0,0xaf,0xf0,0x02,0xff,
 0x27,0xd0,0xc3,0xf8,0xd3,0xb7,0x0a,0x60,0xef,0xe8,0xa9,0x54,0x4a,0xd1,0xe7,
 0x78,0xa1,0x15,0x95,0xe8,0x72,0xf4,0xf1,0x17,0x2a,0x50,0x21,0xf8,0xe3,0xcf,
 0x2d,0xe1,0x2f,0xf4,0xd1,0x21,0xbe,0xf0,0x0f,0xb0,0xe7,0x07,0x7d,0xd4,0x07,
 0xe8,0x87,0x4f,0x97,0xf8,0x20,0x40,0xef,0xa3,0x0a,0x7c,0x00,0xc0,0x7d,0x15,
 0x05,0x7b,0x00,0x40,0xff,0x57,0x50,0x3f,0x20,0x80,0x77,0x48,0xc4,0x5b,0x10,
 0x82,0xfc,0x02,0xb0,0x1f,0x04,0x08,0xff,0x0b,0xd0,0x67,0x50,0x00,0xd6,0x45,
 0xf8,0x3f,0x0a,0x00,0xd8,0x0b,0xbf,0x5b,0x22,0x49,0xe0,0xa6,0xfe,0x37,0x05,
 0x64,0xc1,0xff,0xf7,0xce,0x02,0x0a,0xc1,0xff,0xff,0xd3,0x50,0x02,0x81,0xff,
 0xdf,0xd2,0x01};
}
image create bitmap opened -data {
#define opened_width 13
#define opened_height 13
static unsigned char opened_bits[] = {
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x07, 0x01, 0x04, 0x02, 0x02,
   0x04, 0x01, 0x88, 0x00, 0x50, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00};
}
image create bitmap closed -data {
#define closed_width 13
#define closed_height 13
static unsigned char closed_bits[] = {
   0x18, 0x00, 0x28, 0x00, 0x48, 0x00, 0x88, 0x00, 0x08, 0x01, 0x08, 0x02,
   0x08, 0x01, 0x88, 0x00, 0x48, 0x00, 0x28, 0x00, 0x18, 0x00, 0x00, 0x00,
   0x00, 0x00};
}
image create bitmap sections -data {
#define sect_width 19
#define sect_height 19
static unsigned char sect_bits[] = {
   0x00, 0x00, 0x00, 0xfe, 0x3f, 0x00, 0x02, 0x60, 0x00, 0x02, 0xa0, 0x00,
   0xf2, 0x2f, 0x01, 0x02, 0x20, 0x02, 0xe2, 0xef, 0x03, 0x02, 0x00, 0x03,
   0xf2, 0x0f, 0x03, 0x02, 0x00, 0x03, 0xc2, 0x0f, 0x03, 0x02, 0x00, 0x03,
   0xf2, 0x0f, 0x03, 0x02, 0x00, 0x03, 0xc2, 0x0f, 0x03, 0x02, 0x00, 0x03,
   0xfe, 0xff, 0x03, 0xfc, 0xff, 0x03, 0x00, 0x00, 0x00};
}
image create bitmap history -data {
#define history_width 19
#define history_height 19
static char history_bits[] = {
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x90, 0x0f, 0x00, 0xf0, 0x3f, 0x00, 0xf0, 0x30, 0x00, 0xf0, 0x60, 0x00,
   0xf0, 0x61, 0x00, 0x00, 0x60, 0x00, 0x00, 0x60, 0x00, 0x20, 0x60, 0x00,
   0x60, 0x30, 0x00, 0xc0, 0x3f, 0x00, 0x80, 0x0f, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
}
image create bitmap random -data {
#define random_width 19
#define random_height 19
static char random_bits[] = {
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x01, 0x04, 0x00, 0x01,
   0xf4, 0x78, 0x01, 0x74, 0x70, 0x01, 0xf4, 0x78, 0x01, 0xd4, 0x5d, 0x01,
   0x84, 0x08, 0x01, 0x04, 0x00, 0x01, 0x84, 0x08, 0x01, 0xd4, 0x5d, 0x01,
   0xf4, 0x78, 0x01, 0x74, 0x70, 0x01, 0xf4, 0x78, 0x01, 0x04, 0x00, 0x01,
   0xfc, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
}
set manx(rebus) file|text|home|directory|disk|mail|Macintosh|TeX
image create bitmap fileRebus -data {
#define file_width 12
#define file_height 14
static unsigned char file_bits[] = {
   0xff, 0x00, 0x81, 0x01, 0x81, 0x02, 0x81, 0x04, 0x81, 0x08, 0x81, 0x0f,
   0x01, 0x08, 0x01, 0x08, 0x01, 0x08, 0x01, 0x08, 0x01, 0x08, 0x01, 0x08,
   0x01, 0x08, 0xff, 0x0f};
}
image create bitmap diskRebus -data {
#define noname_width 17
#define noname_height 15
static char noname_bits[] = {
 0xfe,0x7f,0x00,0xe1,0x89,0x00,0xe1,0x09,0x01,0xe1,0x09,0x01,0xe1,0x0f,0x01,
 0x01,0x00,0x01,0xf9,0x3f,0x01,0x05,0x40,0x01,0x05,0x40,0x01,0x05,0x40,0x01,
 0x05,0x40,0x01,0x05,0x40,0x01,0x05,0x40,0x01,0x05,0x40,0x01,0xfe,0xff,0x00};
}
image create bitmap homeRebus -data {
#define woodhouse_width 24
#define woodhouse_height 18
static unsigned char woodhouse_bits[] = {
   0x00, 0x90, 0x00, 0x20, 0x51, 0x03, 0x70, 0x8a, 0x04, 0x50, 0x51, 0x08,
   0x58, 0x84, 0x0a, 0x84, 0x29, 0x12, 0x94, 0xa4, 0x28, 0x42, 0x51, 0x7f,
   0x14, 0xfd, 0x20, 0x74, 0x06, 0x37, 0x54, 0xa1, 0x28, 0x54, 0x8b, 0x2a,
   0x74, 0x81, 0x28, 0x54, 0x61, 0x27, 0x59, 0x0d, 0x20, 0x60, 0x01, 0x9f,
   0x80, 0xf9, 0x00, 0x0a, 0x07, 0x10};
}
image create bitmap textRebus -data {
#define text_width 16
#define text_height 14
static unsigned char text_bits[] = {
   0xfe, 0x7f, 0x02, 0x40, 0x02, 0x40, 0xc2, 0x4f, 0x02, 0x40, 0xf2, 0x4f,
   0x02, 0x40, 0xf2, 0x4f, 0x02, 0x40, 0xf2, 0x4f, 0x02, 0x40, 0xf2, 0x4f,
   0x02, 0x40, 0xfe, 0x7f};
}
image create bitmap directoryRebus -data {
#define file_dir_width 16
#define file_dir_height 13
static unsigned char file_dir_bits[] = {
   0xfc, 0x00, 0x02, 0x01, 0xff, 0xff, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80,
   0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80,
   0xff, 0xff};
}
image create bitmap mailRebus -data {
#define mail_width 16
#define mail_height 13
static unsigned char mail_bits[] = {
   0x00, 0x00, 0xff, 0x7f, 0x03, 0x60, 0x07, 0x70, 0x0d, 0x58, 0x39, 0x4e,
   0x61, 0x43, 0xc1, 0x41, 0x01, 0x40, 0x01, 0x40, 0x01, 0x40, 0xff, 0x7f,
   0x00, 0x00};
}
image create bitmap macintoshRebus -data {
#define mac_width 16
#define mac_height 15
static unsigned char mac_bits[] = {
   0xf8, 0x1f, 0x04, 0x20, 0xf4, 0x2f, 0x14, 0x28, 0x54, 0x29, 0x14, 0x28,
   0x54, 0x28, 0x14, 0x28, 0xf4, 0x2f, 0x04, 0x20, 0x04, 0x20, 0x04, 0x2f,
   0x04, 0x20, 0xf8, 0x1f, 0xf8, 0x1f};
}
image create bitmap texRebus -data {
#define tex_width 16
#define tex_height 13
static unsigned char tex_bits[] = {
   0x3f, 0xee, 0x2d, 0x4c, 0x0c, 0x3c, 0xfc, 0x3b, 0x6c, 0x1a, 0x6c, 0x30,
   0x6c, 0x39, 0xec, 0x79, 0x6c, 0x65, 0x7e, 0xee, 0x60, 0x00, 0x60, 0x02,
   0xf0, 0x03};
}
set manx(solaris-bindings) {
# volume titles for Solaris
# written by Will C Lauer (wcl@cadre.com)
#
# With its default settings TkMan collects all volumes starting
# with the same character under a single section (for instance,
# 1, 1b, 1c, 1f, 1m and 1s are all collected under section 1).
# If multiple volumes share the same initial character
# in their man(manList) abbreviation, these
# sections are separated out in the Volumes menu.  The settings
# below separate out all volumes for Solaris.

# New users (those without ~/.tkman startup files) pick up these
# settings automatically.  The settings can also be interpolated
# into an existing startup file manually.

 
set man(manList) {1 1b 1c 1f 1g 1m 1s 2 3 3b 3c 3e 3f 3g 3i 3k 3l 3m 3n 3r 3s 
                  3t 3w 3x 4 4b 5 6 7 8 8c 8s 9 9e 9f 9s l o n p}
set man(manTitleList) {
        "User Commands" "BSD Compat Commands" Communications "FLMI Commands" 
        "Graphics/CAD Commands" "Maintenance Commands" "SunOS Specific Commands"
		"System Calls" Subroutines "BSD Compatibility" "Standard Library"
        "ELF Subroutines" "Fortran Subroutines" "Regexp Subroutines" 
        "Intl Subroutines" "Kvm Subroutines" "Lightweight Processes Subroutines"
        "Math Subroutines" "Networking Subroutines" 
        "Realtime Subroutines" "Standard I/O Subroutines" 
        "Threads Subroutines" "C Subroutines" "Misc Subroutines" 
        "File Formats" "BSD File Formats" "Headers, Tables, and Macros"
        "Games and Demos" "Devices/Special Files" "Maintenance Procedures"
        "Maintenance Procedures" "Maintenance Procedures"
        "DDI/DKI (Device Drv Interfaces)" 
        "DDI/DKI Entry Points" "DDI/DKI Kernel Functions"
        "DDI/DKI Data Structures"
        Local Old New Public
}

set man(subsect) -b
}
set manx(solaris25-bindings) {
# volume titles for Solaris 2.5 and 2.5.1
# written by Peter Dyballa (pete@thi.informatik.uni-frankfurt.de)
# on October 10 1997.
#
# With its default settings TkMan collects all volumes starting
# with the same character under a single section (for instance,
# 1, 1b, 1c, 1f, 1m and 1s are all collected under section 1).
# If multiple volumes share the same initial character
# in their man(manList) abbreviation, these
# sections are separated out in the Volumes menu.  The settings
# below separate out all volumes for Solaris 2.5 and 2.5.1.

# New users (those without ~/.tkman startup files) pick up these
# settings automatically.  The settings can also be interpolated
# into an existing startup file manually.

 
set man(manList) {1 1b 1c 1f 1m 1s 2 3 3b 3c 3e 3g 3i 3k 3m 3n 3r 3s
                  3t 3x 4 4b 5 6 7 7d 7fs 7i 7m 7p 9 9e 9f 9s l n}
set man(manTitleList) {
        "User Commands" "BSD Compat Commands" Communications
        "FMLI Commands" "Maintenance Commands" "SunOS Specific Commands"
	"System Calls" Subroutines "BSD Subroutines" "Standard C Library"
        "ELF Subroutines" "Regexp Subroutines" "Intl Subroutines"
        "Kvm Subroutines" "Math Subroutines" "Networking Subroutines" 
        "Realtime Subroutines" "Standard I/O Subroutines"
        "Threads Subroutines" "Specialized Subroutines" "File Formats"
        "plot graphics interface" "Headers, Tables, and Macros"
        "Games and Demos" "Devices/Special Files" "STREAMS/Device Drivers"
        "SunOS File Systems" ioctl "STREAMS modules" "Network Protocols"
        "DDI/DKI (Device Drv Interfaces)" "DDI/DKI Entry Points"
        "DDI/DKI Kernel Functions" "DDI/DKI Data Structures" Local New
}

set man(subsect) -b
}
set manx(solaris26-bindings) {
# volume titles for Solaris 2.6
# written by Peter Dyballa (pete@thi.informatik.uni-frankfurt.de)
# on October 10 1997.
#
# With its default settings TkMan collects all volumes starting
# with the same character under a single section (for instance,
# 1, 1b, 1c, 1f, 1m and 1s are all collected under section 1).
# If multiple volumes share the same initial character
# in their man(manList) abbreviation, these
# sections are separated out in the Volumes menu.  The settings
# below separate out all volumes for Solaris 2.6.

# New users (those without ~/.tkman startup files) pick up these
# settings automatically.  The settings can also be interpolated
# into an existing startup file manually.

 
set man(manList) {1 1b 1c 1f 1m 1s 2 3 3b 3c 3e 3g 3k 3m 3n 3r 3s 3t 3x
                  3xc 3xn 4 4b 5 6 7 7d 7fs 7i 7m 7p 9 9e 9f 9s l n}
set man(manTitleList) {
        "User Commands" "BSD Compat Commands" Communications
        "FMLI Commands" "Maintenance Commands" "SunOS Specific Commands"
	"System Calls" Subroutines "BSD Subroutines" "Standard C Library"
        "ELF Subroutines" "Regexp Subroutines" "Kvm Subroutines"
        "Math Subroutines" "Networking Subroutines"  "Realtime Subroutines"
        "Standard I/O Subroutines" "Threads Subroutines" "Specialized Subroutines"
        "X/Open Curses Subroutines" "X/Open Networking Subroutines" "File Formats"
        "plot graphics interface" "Headers, Tables, and Macros"
        "Games and Demos" "Devices/Special Files" "STREAMS/Device Drivers"
        "SunOS File Systems" ioctl "STREAMS modules" "Network Protocols"
        "DDI/DKI (Device Drv Interfaces)" "DDI/DKI Entry Points"
        "DDI/DKI Kernel Functions" "DDI/DKI Data Structures" Local New
}

set man(subsect) -b
}
set manx(solaris28-bindings) {
# volume titles for Solaris 2.8
# contributed by Jongki Suwandi of Sun
# on 24 May 2000

set man(manList) {
	1 1b 1c 1f 1g 1m 1s
	2
	3 3aio 3b 3bsm 3c 3cfgadm 3cpc 3curses 3devid 3devinfo 3dl
	3dmi 3door 3e 3elf 3exacct 3ext 3f 3g 3gen 3gss 3head 3i
	3k 3krb 3kstat 3kvm 3l 3layout 3ldap 3lib 3libucb 3m 3mail
	3malloc 3mp 3n 3nsl 3pam 3plot 3proc 3r 3rac 3resolv 3rpc
	3rt 3s 3sched 3sec 3secdb 3slp 3snmp 3socket 3t 3thr 3tnf
	3ucb 3volmgt 3w 3x 3xc 3xcurses 3xfn 3xn 3xnet
	4 4b
	5
	6
	7 7b 7d 7fs 7i 7m 7p
	8 8c 8s
	9 9e 9f 9s
	l n o p
}

set man(manTitleList) {
	"User Commands"
	"SunOS/BSD Compatibility Package Commands"
	"Communication Commands"
	"FMLI Commands"
	"Graphics and CAD Commands"
	"Maintenance Commands"
	"SunOS Specific Commands"
	"System Calls"
	"Introduction to Library Functions"
	"Asynchronous I/O Library Functions"
	"SunOS/BSD Compatibility Library Functions"
	"Security and Auditing Library Functions"
	"Standard C Library Functions"
	"Configuration Administration Library Functions"
	"CPU Performance Counters Library Functions"
	"Curses Library Functions"
	"Device ID Library Functions"
	"Device Information Library Functions"
	"Dynamic Linking Library Functions"
	"DMI Library Functions"
	"Door Library Functions"
	"C Library Functions"
	"ELF Library Functions"
	"Extended Accounting File Access Library Functions"
	"Extended Library Functions"
	"Fortran Library Routines"
	"C Library Functions"
	"String Pattern-Matching Library Functions"
	"Generic Security Services API Library Functions"
	"Headers"
	"Wide Character Functions"
	"Kernel VM Library Functions"
	"Kerberos Library Functions"
	"Kernel Statistics Library Functions"
	"Kernel VM Library Functions"
	"Lightweight Processes Library"
	"Layout Service Library Functions"
	"LDAP Library Functions"
	"Interface Libraries"
	"SunOS/BSD Compatibility Interface Libraries"
	"Mathematical Library Functions"
	"User Mailbox Library Functions"
	"Memory Allocation Library Functions"
	"Integer Mathematical Library Functions"
	"Network Functions"
	"Networking Services Library Functions"
	"PAM Library Functions"
	"Graphics Interface Library Functions"
	"Process Control Library Functions"
	"Realtime Library"
	"Remote Asynchronous Calls Library Functions"
	"Resolver Library Functions"
	"RPC Library Functions"
	"Realtime Library Functions"
	"Standard I/O Functions"
	"LWP Scheduling Library Functions"
	"File Access Control Library Functions"
	"Security Attributes Database Library Functions"
	"Service Location Protocol Library Functions"
	"SNMP Library Functions"
	"Sockets Library Functions"
	"Threads Library"
	"Threads Library Functions"
	"TNF Library Functions"
	"SunOS/BSD Compatibility Library Functions"
	"Volume Management Library Functions"
	"C Library Functions"
	"Miscellaneous Library Functions"
	"X/Open Curses Library Functions"
	"X/Open Curses Library Functions"
	"XFN Interface Library Functions"
	"X/Open Networking Services Library Functions"
	"X/Open Networking Services Library Functions"
	"File Formats"
	"SunOS/BSD Compatibility Package File Formats"
	"Headers, Tables, and Macros"
	"Games and Demos"
	"Device and Network Interfaces"
	"SunOS/BSD Compatibility Special Files"
	"Devices"
	"File Systems"
	"Ioctl Requests"
	"STREAMS Modules"
	"Protocols"
	"Maintenance Procedures"
	"Maintenance Procedures"
	"Maintenance Procedures"
	"Device Driver Interfaces"
	"Driver Entry Points"
	"Kernel Functions for Drivers"
	"Data Structures for Drivers"
	"Local Commands"
	"Old"
	"New"
	"Public"
}
}
set manx(irix-bindings) {
#
# Add the SGI's magically-appearing catman volumes and directories,
# a multiyear project of Paul Raines (raines@slac.stanford.edu),
# Craig Ruff (cruff@ncar.ucar.edu), and Scott Nelson (nelson18@llnl.gov)
#

# New users (those without ~/.tkman startup files) pick up these
# settings automatically.  The settings can also be interpolated
# into an existing startup file manually.  Unless you have numerous
# highlights and shortcuts, it probably wouldn't hurt to replace
# the existing startup file if interpolation would be too laborious.


set man(buttbg) gray75
set man(guibg) gray90
set man(textbg) white
set man(manList) {1 2 3 4 5 6 7 8 l o n p D}
set man(manTitleList) {
	"User Commands"  "System Calls"  Subroutines  Devices  "File Formats" 
	Games  Miscellaneous  "System Administration"  Local  Old  New  Public
	"Device Drivers"
}

manDot


### your additions go below

# If you don't want a million volumes popping up in the list, simply delete
# the line that adds that volume.  The man pages in that volume will be
# grouped with the next most specific volume.  For instance, if 1M doesn't
# exist, those pages are placed in volume 1; likewise if a 3Xm doesn't exist
# but an Xm group does.

manDescAddSects {
	{1L  "Commands (Local)"}
	{1P  "Commands (Programmer)"}
	{1M  "Commands (Admin)"}
	{1X  "Commands (X11)"}
	{1Xm "Commands (Xm)"}
	{1Iv "Commands (Inventor)"}
	{1ex "Commands (explorer)"}
	{1dm "Commands (dmedia)"}
} after 1

manDescAddSects {{2f "System Calls (ftn)"}} after 2

manDescAddSects {
	{3dm  "Subroutines (Digital Media)"}
	{3L   "Subroutines (local)"}
	{3X   "Subroutines (X11)"}
	{3Xt  "Subroutines (Xt)"}
	{3Xm  "Subroutines (Motif)"}
	{3Xi  "Subroutines (Xirisw)"}
	{3Xo  "Subroutines (misc X)"}
	{3XS  "Subroutines (X SGI)"}
	{3Vk  "Subroutines (ViewKit)"}
	{3cc  "Subroutines (C++)"}
	{3Iv  "Subroutines (Inventor)"}
	{3ex  "Subroutines (explorer)"}
	{3ogl "Subroutines (OpenGL)"}
	{3gl  "Subroutines (GL)"}
	{3pex "Subroutines (pex)"}
	{3f   "Subroutines (ftn)"}
	{3l   "Subroutines (libblas)"}
	{3il  "Subroutines (il)"}
	{3comp "Subroutines (comp)"}
	{3n   "Subroutines (nonstandard)"}
	{3lib "Subroutines (lib)"}
	{3m   "Subroutines (misc)"}
} after 3

manDescAddSects {
	{4L   "Devices (Local)"}
	{4dm  "Devices (Digital Media)"}
	{4ex  "Devices (Explorer)"}
} after 4

manDescAddSects {
	{5L  "File Formats (Local)"}
	{5Xm "File Formats (Motif)"}
} after 5

manDescAddSects {{7L  "Miscellaneous (Local)"}} after 7

manDescAddSects {{8L  "System Administration (Local)"}} after 8

manDescAddSects {{gnu "GNU stuff"}}



# All directories in the catman hierarchy are matched against
# the volume-pattern pairs below.  If there is a match for the
# directory in the same numerical volume, then the directory is
# grouped with that volume.  Otherwise, a match in any volume
# is taken.  If the directory doesn't match any pattern, it
# is placed in next most specific grouping.  If you edit this list,
# place more general groupings after more specific ones.

manDescSGI {
	{ 1P /p_man/*1* }
	{ 1M /a_man/*1* }
	{ 2 2/standard }
	{ 3dm 3dm/* }
	{ 3Xo {Xau Xext Xi Xnmbx} }
	{ 3XS Sg* }
	{ 3Vk Vk }
	{ 3cc c++ }
	{ 3l libblas }
	{ 3ogl {OpenGL widget} }
	{ 3 p_man/*3*/standard }
	{ 3gl 3/standard }
	{ 3n 3/nonstandard }
	{ 3il il }
	{ 3Xi Xirisw }
	{ 3lib lib }
	{ 3m {3b 3c 3g 3n 3p 3s 3t 3w 3x}}
	{ 3pex pex }
	{ 3comp comp }

	{ f ftn }
	{ Iv Inventor }
	{ ex explorer }
	{ dm {dmedia audio video movie midi} }
	{ X {X X11} }
	{ L {/local* /alt*} }
	{ Xt Xt }
	{ Xm Xm }
	{ gnu gnu }
}
}
set manx(sco-bindings) {
#
# calculate standard SCO UNIX modifications,
# based on information from Bela Lubkin
#

# New users (those without ~/.tkman startup files) pick this up
# automatically.  The code can also be interpolated into an existing
# startup file manually.


### your additions go below

set manx(dirnameindex) 4; # should be set already, but just in case

# Compute sections based on system settings.
set man(manList) ""
set man(manTitleList) ""

#  grep ORDER= /etc/default/man
#  ORDER=C:S:CP:CT:M:F:HW:DOS:UCB:LOCAL:ADM:TCL:ADMN:ADMP:SFF:TC:NADM:NF:NC:PADM:X:XC:MERGE:AS:net:FP:C++:CDMT:Xext:Xm:Xmu:XS:Xt:NET:SLIB:SSC:NS:SAPD

set manx(sco-master) {
	{1 "User Commands"} {3 "Functions"} {4 "File Formats"} {5 Support Files"} {7 "Packages"}
	{A "Administration"}
	{ADM "Operating system administration"}
	{ADMN "TCP/IP administration commands"}
	{ADMP "TCP/IP network protocols"}
	{C "Operating system commands, utilities"}
	{C++ "C++ library"}
	{CDMT "Custom Distribution Mastering Toolkit"}
	{CP "Programming commands"}
	{F "File formats"}
	{FP "Programming file formats"}
	{G Games}
	{H "Hardware and Drivers"}
	{HW "Device drivers, hardware"}
	{L "Local Commands"}
	{LMC "LAN Manager Client commands"}
	{M "Miscellaneous"}
	{MERGE "SCO Merge commands"}
	{NADM "NFS network administration commands"}
	{NC "NFS network user commands"}
	{NET "TLI/XTI transport stack library"}
	{NF "NFS file formats"}
	{NS "NFS, NIS, RPC, XDR network library"}
	{NWG "SCO Gateway for NetWare commands"}
	{PADM "IPX/SPX commands"}
	{PCI "PC-Interface commands"}
	{S "Operating system calls, library"}
	{SAPD "DCE SAP library"}
	{SFF "TCP/IP file formats"}
	{SLIB "Socket library"}
	{SSC "Socket system calls"}
	{TC "TCP/IP network user commands"}
	{TCL "SCO Visual Tcl commands"}
	{WABI "SCO Wabi commands"}
	{X "X server commands"}
	{XC "X client commands"}
	{Xext "X Extensions library"}
	{Xm "OSF/Motif commands, library"}
	{Xmu "X library (miscellaneous utilities)"}
	{XS "X library"}
	{Xt "X Toolkit Intrinsics library"}
}

# build default list based on ORDER= in /usr/default/man
set scolist ""
set manx(sco-config) "/etc/default/man"
#set manx(sco-config) "tmp"
if [file readable $manx(sco-config)] {
	set fid [open $manx(sco-config)]
	while {![eof $fid]} {
		set line [gets $fid]
		if [regexp  "^\[ \t]*ORDER\[ \t]*=\[ \t]*(.*)" $line all tmp] {
			set scolist $tmp
			# want last ORDER= line so don't break
		}
	}
	close $fid

	if {$scolist!=""} {
		# build list in given order
		foreach i [split [string trim $scolist] ":"] {
			if {[lsearch $man(manList) $i]==-1} {	# no duplicates
				lappend man(manList) $i
				if {[set title [lassoc $manx(sco-master) $i]]==""} { set title $i }
				lappend man(manTitleList) $title
			}
		}
	}
}

# if can't find ORDER, build up default list from master list
if {$scolist==""} {
	foreach i $manx(sco-master) {
		lappend man(manList) [lfirst $i]
		lappend man(manTitleList) [lsecond $i]
	}
}
}





set sb(key,*) "state multiple modifiers in this order: S, C, M, A"


set sb(key,C-x) exchangepointandmark
set sb(key,C-space) setmark
set sb(key,-Delete) pageup
set sb(key,C-h) pageup
set sb(key,M-v) pageup
set sb(key,-BackSpace) pageup
set sb(key,-space) pagedown
set sb(key,C-v) pagedown
set sb(key,-Escape) searchkill
set sb(key,C-g) searchkill
set sb(key,C-n) nextline
set sb(key,C-p) prevline
set sb(key,-Up) prevline
set sb(key,-Down) nextline
set sb(key,-Left) prevline
set sb(key,-Right) nextline
set sb(key,C-s) incrsearch
set sb(key,C-r) revincrsearch
set sb(key,M-question) help
set sb(key,-Help) help
set sb(key,C-l) clearscreen



set sb(key,C-f) pagedown
set sb(key,C-b) pageup



set sb(key,-F27) pagestart
set sb(key,-F29) pageup
set sb(key,-F35) pagedown
set sb(key,-R13) pageend
set sb(key,-F33) pageend


set sbx(wrap-msg) "No more matches; try again to wrap around"


set sb(key,-Prior) pageup
set sb(key,-Next) pagedown
set sb(key,-Home) pagestart
set sb(key,-End) pageend
set sb(key,M-less) pagestart
set sb(key,M-greater) pageend

foreach e [array names sb] {
set sbdef($e) $sb($e)
}



proc searchboxSearch {pat regexp casesen tag t {wmsg ""} {wcnt ""} args} {
global sbx

if {$args eq "{}"} {set args ""}

if {$casesen==-1} {set casesen ![string is lower $pat]}
set caseopt [expr !$casesen?"-nocase":""]
if {$regexp} {set type "regexp"} {set type "exact"}

if {$pat eq ""} {
winstderr $wmsg "Nothing to search for!  Type in a [expr $regexp?{regular expression}:{string}]."
return 0
}


if {![string match "TAG:*" $pat] && $type eq "regexp" && [catch {regexp $pat bozomaniac}]} {
winstderr $wmsg "Malformed regular expression."
return 0
}

$t tag remove $tag 1.0 end

set cnt 0


if {[regexp "^TAG:(.*)" $pat all ptag]} {
$t tag remove $tag 1.0 end
set cnt 0
foreach wtag [$t tag names] {
if {[string match $ptag $wtag]} {
foreach {s e} [$t tag ranges $wtag] {$t tag add $tag $s $e; incr cnt}
}
}

} else {
set index 1.0
set len 0
while {[set index [eval "$t search -forwards -$type $caseopt $args -count len -- {$pat} {$index+$len chars} end"]] ne ""} {
$t tag add $tag $index "$index + $len chars"
incr cnt
}
}


if {$cnt==0} {set txt "no matches"} else {set txt "$cnt [textmanip::plural $cnt match es]"}
if {$wcnt ne ""} {$wcnt configure -text $txt}

set sbx(ratend$t) 0; set sbx(ratstart$t) 0

return $cnt
}




proc searchboxNext {tag t {wmsg ""} {yoff ""}} {
global sbx

if {![llength [$t tag ranges $tag]]} { winstderr $wmsg "No matches!"; return }

if {$yoff eq ""} {
set yoff [winfo height $t]; set start [$t index @0,$yoff]
if {[set prev [$t tag prevrange search @0,$yoff @0,0]]!=""} {set start [$t index [lsecond $prev]+1c]}
} else { set start [$t index @0,$yoff] }
set hit [$t tag nextrange $tag $start]
if {$hit eq ""} {
if {$sbx(ratend$t)} {
set hit [$t tag nextrange $tag 1.0]
set sbx(ratend$t) 0
} else {
set sbx(ratend$t) 1
if {[$t bbox 1.0] eq ""} {winstderr $wmsg $sbx(wrap-msg)} {searchboxNext $tag $t $wmsg $yoff}
}
}
if {$hit!=""} {
$t mark set hit [lindex $hit 0]
$t see hit
}
}

proc searchboxPrev {tag t {wmsg ""}} {
global sbx

if {![llength [$t tag ranges $tag]]} { winstderr $wmsg "No matches!"; return }

set hit [$t tag prevrange $tag [$t index @0,0]]
if {$hit eq ""} {
if {$sbx(ratstart$t)} {
set hit [$t tag prevrange $tag end]
set sbx(ratstart$t) 0
} else {
set sbx(ratstart$t) 1
if {[$t bbox end-1c] eq ""} {winstderr $wmsg $sbx(wrap-msg)} {searchboxPrev $tag $t $wmsg}
}
}

if {$hit!=""} {
$t mark set hit [lindex $hit 0]
$t see hit
}
}



proc searchboxKeyNav {m k casesen t {wmsg ""} {firstmode 0} args} {
global sb sbx

if {$args eq "{}"} {set args ""}

if {[regexp {(Shift|Control|Meta|Alt|NunLock)_.} $k]} {return 0}
if {![info exists sbx(try$t)]} {
set sbx(try$t) 0
set sbx(vect$t) 1
set sbx(lastkeys$t) ""
set sbx(iatstart$t) 0; set sbx(iatend$t) 0
if ![info exists sbx(lastkeys-old$t)] {set sbx(lastkeys-old$t) ""}
}


if {!$firstmode && ($sbx(try$t) || $sbx(lastkeys$t) ne "")} {
switch -exact -- $k {
space {set k " "}
BackSpace -
Delete {
set k ""
set last [expr [string length $sbx(lastkeys$t)]-2]
set sbx(lastkeys$t) [string range $sbx(lastkeys$t) 0 $last]
set sbx(try$t) 1
}
default { if {$m eq "" || $m eq "S"} {set k [name2char $k]} }
}
}


set m [string trimright $m "SM"]; # strip shift and numlock as a modifier
set mk $m-$k
if {$m eq "literal"} {set op $k} \
elseif {[info exists sb(key,$mk)]} {set op $sb(key,$mk)} \
elseif {$m eq "" && [string length $k]<=1} {set op default} \
else {return 0}

switch -exact -- $op {
exchangepointandmark {
set tmp [$t index @0,0]
$t yview xmark
update
$t mark set xmark $tmp
}
setmark {$t mark set xmark [$t index @0,0]}
pageup {$t yview scroll -1 pages}
pagedown {$t yview scroll 1 pages}
pagestart {$t yview moveto 0}
pageend {$t yview moveto 1}
searchkill {
if {$sbx(lastkeys$t) ne ""} {set sbx(lastkeys-old$t) $sbx(lastkeys$t)}
set sbx(lastkeys$t) ""; set sbx(try$t) 0
winstdout $wmsg ""
}
clearscreen {winstdout $wmsg ""}
nextline {$t yview scroll 1 units}
prevline {$t yview scroll -1 units}
default {
if {$op eq "incrsearch"} {
if {$sbx(try$t) && $sbx(lastkeys$t) eq ""} {set sbx(lastkeys$t) $sbx(lastkeys-old$t)}
set sbx(vect$t) 1; set sbx(try$t) 1
} elseif {$op eq "revincrsearch"} {
if {$sbx(try$t) && $sbx(lastkeys$t) eq ""} {set sbx(lastkeys$t) $sbx(lastkeys-old$t)}
set sbx(vect$t) -1; set sbx(try$t) 1
} elseif {$firstmode} {
set sbx(lastkeys$t) $k
set sbx(try$t) 1
} elseif {$sbx(try$t)} {
append sbx(lastkeys$t) $k
}

set keys $sbx(lastkeys$t)
if {$casesen==-1} {set casesen ![string is lower $keys]}
set caseopt [expr !$casesen?"-nocase":""]
if {$sbx(try$t)==0 && $keys eq ""} {return 0}
winstdout $wmsg "Searching for \"$keys\" ..."


if {$firstmode} {
set start 1.0; set end end
} elseif {[llength [set ranges [$t tag ranges isearch]]]} {
set start [lindex $ranges 0]; set end 1.0
if {$op eq "incrsearch"} {set start [$t index "$start+1c"]}
if {$sbx(vect$t)==1} {set end "end"}
} else {
if {$sbx(vect$t)==1} {
set start [$t index @0,0]; set end "end"
} else {
set start [$t index @0,[winfo height $t]]; set end "1.0"
}
}

set dir [expr {$sbx(vect$t)==1?"-forwards":"-backwards"}]
set type [expr $firstmode?"-regexp":"-exact"]
set pfx [expr $firstmode?"^":""]
set search "$t search $dir $type $caseopt -count klen $args -- [list $pfx$keys] $start"
set found [eval "$search $end"]
set anywhere [eval $search]

if {$anywhere ne ""} {
if {$found ne ""} {
$t tag remove isearch 1.0 end
$t tag add isearch $found "$found + $klen c"
$t mark set hit $found
$t see hit
set sbx(iatstart$t) 0; set sbx(iatend$t) 0
} else {
if {$sbx(vect$t)==1} {
if {$sbx(iatstart$t)} {
$t yview moveto 0; $t tag remove isearch 1.0 end
return [searchboxKeyNav $m $k $casesen $t $wmsg $firstmode]
} else {
winstderr $wmsg $sbx(wrap-msg)
set sbx(iatstart$t) 1
}
} else {
if {$sbx(iatend$t)} {
$t yview moveto 1; $t tag remove isearch 1.0 end
return [searchboxKeyNav $m $k $casesen $t $wmsg $firstmode]
} else {
winstderr $wmsg $sbx(wrap-msg)
set sbx(iatend$t) 1
}
}
}
} else {
$t tag remove isearch 1.0 end
winstderr $wmsg "\"$keys\" not found"
set sbx(try$t) 0
}
}
}

return 1
}




proc searchboxSaveConfig {fid} {
global sb sbx sbdef

puts $fid "#\n# SearchBox\n#\n"
foreach i [lsort [array names sb]] {
set co ""
if {[info exists sbdef($i)] && $sbdef($i) eq $sb($i)} {set co "#"}
puts $fid "${co}set sb($i) [list $sb($i)]"
}
puts $fid "\n"
}



if {![llength [info procs winstdout]]} {

proc winstderr {w msg {type "bell & flash"}} {
if {![winfo exists $w]} return
set bell [string match "*bell*" $type]
set flash [string match "*flash*" $type]

set fg [$w cget -foreground]; set bg [$w cget -background]

set msgout [string range $msg 0 500]
if {[string length $msg]>500} {
append msgout " ... (truncated; full message sent to stdout)"
puts stderr $msg
}
winstdout $w $msgout
if {$flash} {$w configure -foreground $bg -background $fg}
if {$bell} bell
if {$flash} {
update idletasks; after 500
$w configure -foreground $fg -background $bg
}
}

proc winstdout {w {msg AnUnLiKeMeSsAgE} {update 0}} {
if {![winfo exists $w]} return
if {$msg ne "AnUnLiKeMeSsAgE"} {
$w configure -text $msg
if {$update} { update idletasks }
}
return [$w cget -text]
}

}





set findx(matches) {}
set findx(expr) {}
set findx(rexpr) {}
set findx(seen) 0
proc findfile {dir filepattern} {
find $dir [subst -nocommands {[string match $filepattern \$file]}]
}
proc find {dir expr {rexpr 1}} {
global findx
set olddir [pwd]

set findx(matches) {}
set findx(expr) $expr
set findx(rexpr) $rexpr
set findx(seen) 0
find1 $dir 0 $olddir

return $findx(matches)
}

proc find1 {dir depth updir} {
global findx

if {$findx(rexpr) eq ""} return
if {[catch {cd $dir}]} return
set f(dir) $dir
foreach file [glob -nocomplain *] {
incr findx(seen)
if {[catch {file lstat $file f}]} continue
set subupdir ..; if {$f(type) eq "link" && [file isdirectory $file]} {set f(type) "directory"; set subupdir [pwd]}
set f(tail) $file
set relpath [file join $dir $file]
if {[subst $findx(expr)]} {lappend findx(matches) $relpath}

if {[file isdirectory $relpath]} {
foreach match [find1 $relpath [expr {$depth+1}] $subupdir] {lappend findx(matches) $match}
}
}
cd $updir
}


proc pipeexp {p} {
set p [string trim $p]

set expp ""
foreach i $p {
if {[regexp {^[.~/$]} $i]} {lappend expp [fileexp $i]} \
else {lappend expp $i}
}
return $expp
}

proc assert {bool msg {boom 0}} {
if {!$bool} {
puts stderr $msg
if {$boom} {exit 1}
}
}

proc fileexp {f} {
global env

set f [string trim $f]
set l [string length $f]
set expf ""

set dir [pwd]
foreach i [split $f "/"] {
switch -glob $i {
"" {set dir ""}
{[A-Za-z]:} {set dir "$i"}
~  {set dir $env(HOME)}
$* {set val $env([string trim [string range $i 1 end] ()])
if {[string match /* $val]} {set dir $val} else {append expf /$val)}}
.  {set dir $dir}
.. {set dir [file dirname $dir]}
default {append expf /$i}
}
}

return $dir$expf
}



proc filetail {f} {
set tail [file tail $f]
if {[string match */ $f]} {set tail ""}
return $tail
}
proc filedirname {f} {
set dirname [file dirname $f]
if {[string match ?*/ $f]} {set dirname [string range $f 0 [expr {[string length $f]-2}]]}
return $dirname
}

proc filecomplete {f} {
set expf [fileexp [filedirname $f]]/[filetail $f]
set posn [string last [filetail $f] $f]; if {[string match */ $f]} {set posn [string length $f]}
set l [glob -nocomplain $expf*]
set ll [llength $l]

if {!$ll} {
set tail ""
} elseif {$ll==1} {
set tail [file tail $l]
if {[file isdirectory $l]} {append tail /}
} else {
set lf [lfirst $l]; set lfl [string length $lf]
set last $lfl
set ni [expr {[string last / $lf]+1}]
foreach i $l {
for {set j $ni} {$j<=$last} {incr j} {
if {[string index $lf $j] ne [string index $i $j]} break
}
set last [min $last [expr {$j-1}]]
}
set tail [filetail [string range [lfirst $l] 0 $last]]
}

if {$posn>0 && $ll} {
set tail [string range $f 0 [expr {$posn-1}]]$tail
}

if {$ll<2} {return $tail} else {return "$tail $l"}
}


proc tr {s c1 c2} {
regsub -all "\[$c1\]" $s $c2 s2
return $s2
}

proc bolg {f {l ""}} {
if {$l eq ""} {global file; set l $file(globList)}

foreach i $l {
if {[regsub ([glob -nocomplain $i])(.*) $f "$i\\2" short]} {return $short}
}
return $f
}


proc setinsert {l i e} {
return [linsert [lfilter $e $l] $i $e]
}


proc unsplit {l c} {
foreach i $l {
append l2 $i $c
}
return [string range $l2 0 [expr {[string length $l2]-2}]]
}

proc bytes2prefix {x} {
set pfx {bytes KB MB GB TB QB}
set k 1024.0
set sz $k

if {$x<$k} {return "$x bytes"}

set y BIG
for {set i 0} {$i<[llength $pfx]} {incr i} {
if {$x<$sz} {
return [format " %0.1f [lindex $pfx $i]" [expr {$x/($sz/$k)}]]
}
set sz [expr {$sz*$k}]
}
}




proc quote {x} {return $x}

proc uniqlist {l} {
set e ""
set l2 ""
foreach i $l {
if {$e ne $i} {
lappend l2 $i
set e $i
}
}
return $l2
}


proc min {args} {
if {[llength $args]==1} {set args [lindex $args 0]}
set x [lindex $args 0]
foreach i $args {
if {$i<$x} {set x $i}
}
return $x
}

proc avg {args} {
set sum 0.0

if {[string $args ""]} return

foreach i $args {set sum [expr {$sum+$i}]}
return [expr {($sum+0.0)/[llength $args]}]
}

proc max {args} {
if {[llength $args]==1} {set args [lindex $args 0]}
set x [lindex $args 0]
foreach i $args {
if {$i>$x} {set x $i}
}
return $x
}


proc lfirst {l} {return [lindex $l 0]}
proc lsecond {l} {return [lindex $l 1]}
proc lthird {l} {return [lindex $l 2]}
proc lfourth {l} {return [lindex $l 3]}
proc lfifth {l} {return [lindex $l 4]}
proc lsixth {l} {return [lindex $l 5]}
proc lseventh {l} {return [lindex $l 6]}
proc lrest {l} {return [lrange $l 1 end]}

proc llast {l} {
return [lindex $l end]
}

proc setappend {l e} {
return "[lfilter $e $l] $e"
}

proc lfilter {p l} {
set l2 ""

foreach i $l {
if {![string match $p $i]} "lappend l2 [list $i]"
}
return $l2
}

proc lmatches {p l} {
set l2 ""
foreach i $l { if {[string match $p $i]} {lappend l2 [list $i]} }
return $l2
}

proc lassoc {l k} {
foreach i $l {
if {[lindex $i 0]==$k} {return [lrange $i 1 end]}
}
return ""
}


proc lbssoc {l k} {

foreach i $l {
if {[lindex $i 1]==$k} {return [lindex $i 0]}
}
return ""
}

proc lreverse {l {block 1}} {
set lrev {}
for {set i [expr {[llength $l]-$block}]} {$i>=0} {incr i -$block} {
lappend lrev [lrange $l $i [expr {$i+$block-1}]]
}
set flatten [eval concat $lrev]
return $flatten
}



proc geom2posn {g} {
if {[regexp {(=?\d+x\d+)([-+]+\d+[-+]+\d+)} $g both d p]} {
return $p
} else { return $g }
}

proc geom2size {g} {
if {[regexp {(=?\d+x\d+)([-+]+\d+[-+]+\d+)} $g both d p]} {
return $d
} else { return $g }
}






set name2charList {
minus plus percent ampersand asciitilde at less greater equal
numbersign dollar asciicircum asterisk quoteleft quoteright
parenleft parenright bracketleft bracketright braceleft braceright
semicolon colon question slash bar period underscore backslash
exclam comma
}

proc name2char {c} {
global name2charList

if {[set x [lsearch $name2charList $c]]!=-1} {
return [string index "-+%&~@<>=#$^*`'()\[\]{};:?/|._\\!," $x]
} else {return $c}
}

proc key_state2mnemon {n} {
set mod ""

set trans "S CMA  "; # ignore spaced modifiers

for {set bp 0} {$bp<[string length $trans]} {incr bp} {
set t [string index $trans $bp]
if {$t ne " " && $n&(1<<$bp)} {append mod $t}
}

return $mod
}

proc lmatch {mode list {pattern ""}} {
if {$pattern eq ""} {set pattern $list; set list $mode; set mode "-glob"}
return [expr {[lsearch $mode $list $pattern]!=-1}]
}



proc stringremove {s {c " "}} {
regsub -all -- \\$c $s "" s2
return $s2
}


proc stringregexpesc {s} { 
return [stringesc $s {\||\*|\+|\?|\.|\^|\$|\\|\[|\]|\(|\)|\-}]
}
proc stringesc {s {c {[][\\\${}"]}}} {
regsub -all -- $c $s {\\&} s2
return $s2
}


proc tk_listboxNoSelect args {
foreach w $args {
bind $w <Button-1> {format x}
bind $w <B1-Motion> {format x}
bind $w <Shift-1> {format x}
bind $w <Shift-B1-Motion> {format x}
}
}


proc listboxshowS {lb s {first 0} {cnstr yes}} {
set sz [$lb size]

for {set i $first} {$i<$sz} {incr i} {
if {[string match $s [$lb get $i]]} {
listboxshowI $lb $i $cnstr
return $i
}
}
return -1
}

proc listboxshowI {lb high {cnstr yes}} {
set high [max 0 [min $high [expr {[$lb size]-1}]]]

set hb [lindex [split [$lb cget -geometry] x] 1]
set hx [max 0 [expr {[$lb size]-$hb}]]
if {$cnstr eq "yes"} {set hl [expr {$high<$hb?0:[min $high $hx]}]} else {set hl $high}
$lb select from $high
$lb yview $hl
}

proc listboxreplace {lb index new} {
$lb delete $index
$lb insert $index $new
$lb select from $index
}



proc listboxmove {l1 l2} {
listboxcopy $l1 $l2
$l1 delete 0 end
}

proc listboxcopy {l1 l2} {

$l2 delete 0 end
listboxappend $l1 $l2
catch {$l2 select from [$l1 curselection]}
}

proc listboxappend {l1 l2} {

set size [$l1 size]

for {set i 0} {$i<$size} {incr i} {
$l2 insert end [$l1 get $i]
}
}


option add *Text.borderwidth 2



proc tabgroup {args} {
if {[llength $args]==1} {set wins [lindex $args 0]} else {set wins $args}

set l [llength $wins]
for {set i 0} {$i<$l} {incr i} {
set w [lindex $wins $i]
set pw [lindex $wins [expr {($i-1)%$l}]]
set nw [lindex $wins [expr {($i+1)%$l}]]

bind $w <KeyPress-Tab> "focus $nw; break"
bind $w <Shift-KeyPress-Tab> "focus $pw; break"
}
}


proc winstderr {w msg {type "bell & flash"}} {
if {![winfo exists $w]} return
set bell [string match "*bell*" $type]
set flash [string match "*flash*" $type]

set fg [$w cget -foreground]; set bg [$w cget -background]

set msgout [string range $msg 0 250]
if {[string length $msg]>250} {
append msgout " ... (truncated; full message sent to stdout)"
puts stderr $msg
}
winstdout $w $msgout
if {$flash} {$w configure -foreground $bg -background $fg}
if {$bell} bell
if {$flash} {
update idletasks; after 500
$w configure -foreground $fg -background $bg
}
}

proc winstdout {w {msg AnUnLiKeMeSsAgE} {update 0}} {
if {![winfo exists $w]} return
if {$update eq "update"} {set update 1}

if {$msg ne "AnUnLiKeMeSsAgE"} {
$w configure -text $msg
if {$update} { update idletasks }
}
return [$w cget -text]
}

proc yviewcontext {w l c} {
if {$l eq "sel"} {
set cnt [scan [$w tag ranges sel] %d l]
if {$cnt<=0} return
}

incr l -1; # 0-based!

scan [$w index end] %d n
set prev [expr {$l-$c}]; set next [expr {$l+$c}]

if {$prev>=0} {$w yview -pickplace $prev}
if {$next<=$n} {$w yview -pickplace $next}
$w yview -pickplace $l
}


proc screencenter {xy wh} {
if {$xy eq "x"} {
return [expr {([winfo screenwidth .]-$wh)/2}]
} else {
return [expr {([winfo screenheight .]-$wh)/2}]
}
}


proc cursorBusy {{up 1}} {
if {[. cget -cursor] ne "watch"} {
cursorSet watch; if {$up} {update idletasks}
}
}
proc cursorSet {c {w .}} {
global cursor
set cursor($w) [$w cget -cursor]
$w configure -cursor $c
foreach child [winfo children $w] {cursorSet $c $child}
}
proc cursorUnset {{w .}} {
global cursor
catch {$w configure -cursor $cursor($w)}
foreach child [winfo children $w] {cursorUnset $child}
}

proc configurestate {wins {flag "menu"}} {
set flag0 $flag
foreach w $wins {
set flag $flag0
if {$flag eq "menu"} {
if {[winfo class $w] eq "Menubutton"} {
set m [$w cget -menu]; set end [$m index end]
set flag [expr {$end ne "none" && (![$m cget -tearoff] || $end>0)} ]
} else { set flag 0 }
}
$w configure -state [expr {$flag?"normal":"disabled"}]
}
}


proc smenu {m args} {
if {![winfo exists $m]} {eval menu $m $args}
return $m
}


namespace eval textmanip {

proc plural {cnt word {s ""}} {
if {$cnt!=1 && $cnt!=-1} {
if {$s eq ""} { if {[string equal -nocase [string index $word end] "s"]} {set s "es"} else {set s "s"}}
append word $s
}
return $word
}


proc mon2Month {m} {
set mons {jan feb mar apr may jun jul aug sep oct nov dec}
set Months {January February March April May June July August September October November December}
set ml [string tolower $m]
if {[set x [lsearch -exact $mons $ml]]!=-1} {
set m [lindex $Months $x]
}

return $m
}


proc linebreak {string {breakat 70}} {
set ch 0; set lastw ""
set broke ""

foreach word $string {
if {[string match "*." $lastw]} {append broke " "}

set wlen [string length $word]
if {$ch+$wlen<$breakat} {
if {$ch>0} {append broke " "; incr ch}
append broke $word; incr ch $wlen
} else {
append broke "\n" $word
set ch $wlen
}

set lastw $word
}

return $broke
}


proc recently {then} {
set datainfo "%Y %B %d %H %M %S"
set format "%d %s %d %d %s %s"
set now [clock seconds]
scan [clock format $now -format $datainfo] $format year month day hour min sec
set midnight [clock scan "$day $month"]
scan [clock format $then -format $datainfo] $format oyear omonth oday ohour omin osec

set secday [expr {24*60*60}]
set secmonth [expr {30*$secday}]
set secyear [expr {365*$secday}]

set age [expr {$now-$then}]
if {$age>=[expr {$secyear-2*$secmonth}]} {
set r "$oday $omonth $oyear"
} else {
if {$age>=$secmonth} {
set r "$ohour:$omin, $oday $omonth"
} else {
set r "$ohour:$omin"
if {[expr {$midnight-$secday}]>=$then} {
append r ", $oday $omonth"
} else {
if {$day!=$oday} {
append r " yesterday"
} else { append r ":$osec today" }
}
}
}

return $r
}



set stoplistsrc {
an the 
is am be been being I'm I'll I'd I've are was wasn't were weren't take took taking use used using may might made make can can't could couldn't would wouldn't will won't given gave have having haven't has hasn't had hadn't get got go went come came receive received own
and or both yes yeah neither nor but not no also instead etc
all some many few much more most less least each every only any up down under in out front back top bottom here there over following last next prev previous about still really better worse often usually almost lot little
thing something anything everything one anyone everyone someone time sometime anytime everytime maybe way anyway away
if then than such between because however yet like as just very especially again already well too even
at of to into onto on in by with without for from so 
example
me my we us our they them there there's their this that these those that's which other you your you'll he him he's she her she's it its it's 
who whose what where when why how now
think thought say says said read write wrote feel felt believe believed need needed meet met know knew want wanted do don't doesn't did didn't sit sat stand stood see new current specified same different item entry
please thank people

jan feb mar apr may jun jul aug sep oct nov dec
january february march april may june july august september october november december
mon tue wed thu fri sat sun
monday tuesday wednesday thursday friday saturday sunday
north south east west
am pm tm re

first second third fourth fifth
one two three four five six seven eight nine ten hundred thousand million billion trillion

hi hello


bug file filename path pathname directory dir home program software input output name bin script lib usr user run set command com tcp ip rpc install installed invoke invoked group argument exit id option level local code system list address addressed source binary type var variable machine mode configuration information info char character int void ok sww

date to from subject
org com edu gov mil net


object oriented server protocol client string module class public private protected time database field menu version default print line expression buffer

torithoughts smoe mlether ecto

}


variable singregexp {'?(s|y|ies) }
regsub -all $singregexp [string tolower $stoplistsrc] " " singstoplist
variable stoplist
foreach s $singstoplist {set stoplist($s) ""}
variable freqs
variable we {^[A-Za-z][A-Za-z0-9&_'-]+}; # ...* to be a word, but don't want single-letter words... maybe don't want two- or three-letter words either 
variable ce {[^A-Za-z0-9&_'-]+}

proc wordfreq {txt {top 10}} {
variable singregexp; variable stoplist; variable freqs; variable we; variable ce

update

catch {unset freqs}

regsub -all $ce [string tolower $txt] " " words
regsub -all $singregexp $words " " singwords
set awords {}
foreach word [lsort $singwords] {
if {![info exists stoplist($word)] && [regexp $we $word]} {lappend awords $word}
}

update

set lastword "total"; set cnt [llength $awords]
set freqpairs {}
foreach word $awords {
if {$word ne $lastword} {
lappend freqpairs [list $lastword $cnt]; set freqs($lastword) $cnt
set cnt 0; set lastword $word
}
incr cnt
}
lappend freqpairs [list $lastword $cnt]

update

set freqpairs [lsort -index 1 -integer -decreasing $freqpairs]

return [lrange $freqpairs 0 [expr {$top-1}]]
}


proc summarize {t {n 2} {sol 1.0}} {
variable ce; variable singregexp; variable freqs

set eolrx "^\[-># \t]+|^$|^\[A-Z]\[-a-z]+:|(^|\[ \t]+)(\[\$\"a-z0-9\]|\[A-Z\]\[A-Z\]|\[A-Z\]\[^ \t]\[^ \t]\[^ \t])\[^ \t]*\[.?!\;]\[ \t]*($|\[ \t])"
set important "subject|important|key|central|main"

set sent {}; # triple: text start, text end, score
while {1} {
if {[set eol [$t search -count endcnt -regexp $eolrx $sol end]]==""} break
append eol "+${endcnt}c"

regsub -all $ce [$t get $sol $eol] " " words
regsub -all $singregexp $words " " singwords
set score 0; set wcnt 0; set lastword ""
foreach word [lsort $singwords] {
set lcword [string tolower $word]
if {$lcword!=$lastword && [info exists freqs($lcword)]} {
set bonus 1; if {$word!=$lcword} {set bonus 2; if {$word==[string toupper $word]} {set bonus 3}}
if {[regexp "^($important)" $lcword]} {set bonus [expr {$bonus*10}]}
incr score [expr {$freqs($lcword)*$bonus}]
incr wcnt; set lastword $lcword
}
}
if {$score>0 && $wcnt>=5} {lappend sent [list $sol $eol [expr {$score/($wcnt/5.0)}]]}
set sol $eol
}

set state [$t cget -state]; $t configure -state normal
for {set i [expr {[llength $sent]-1}]} {0 && $i>=0} {incr i -1} {
foreach {sol eol score} [lindex $sent $i] break
$t insert $sol "  ([format %.0f $score]) "
}
$t configure -state $state

return [lrange [lsort -real -decreasing -index 2 $sent] 0 [expr {([llength $sent]*$n)/100}]]
}



proc wdiff {oldline newline {instag "diffa"} {deltag "diffd"} {fuzz 3}} {
set tclesc {[][\\\${}"]}
regsub -all -- $tclesc $oldline {\\&} oldline; regsub -all -- $tclesc $newline {\\&} newline
set diffcnt 0; # count number of words of difference
set oldlinelen [llength $oldline]; set newlinelen [llength $newline]
set newlinefuzz [expr {$newlinelen-$fuzz}]
set linecomp {}

set punct ".,?\;!"
set matchcnt 0
for {set i1 0; set i2 0} {$i1<$oldlinelen && $i2<$newlinelen} {} {
set w1 [lindex $oldline $i1]; set w2 [lindex $newline $i2]
if {$w1==$w2 || [string trim $w1 $punct]==[string trim $w2 $punct]} {incr matchcnt; incr i1; incr i2; continue}


if {$matchcnt} {lappend linecomp "[lrange $newline [expr {$i2-$matchcnt}] [expr {$i2-1}]] " {}; set matchcnt 0}

incr diffcnt

set fIns 0
for {set s $i2} {$s<$newlinefuzz} {incr s} {
if {$w1==[lindex $newline $s] && [lrange $oldline $i1 [expr {$i1+$fuzz-1}]]==[lrange $newline $s [expr {$s+$fuzz-1}]]} {
lappend linecomp "[lrange $newline $i2 [expr {$s-1}]] " $instag
set i2 $s
set fIns 1; break
}
}
if {$fIns} continue
lappend linecomp "$w1 " $deltag
incr i1
}

if {$matchcnt} {lappend linecomp "[lrange $newline [expr {$i2-$matchcnt}] [expr {$i2-1}]] " {}}
if {$i1<$oldlinelen} {lappend linecomp "[lrange $oldline $i1 end] " $deltag}
if {$i2<$newlinelen} {lappend linecomp "[lrange $newline $i2 end] " $instag}



return $linecomp
}


}

option add *Menubutton.relief raised
option add *padX 2
option add *padY 2
option add *Button.padX 2
option add *Button.padY 2
option add *Menubutton.padX 2
option add *Menubutton.padY 2
option add *Radiobutton.padX 2
option add *Radiobutton.padY 2

set manx(searchtags) {
"version changes" diff*   highlights highlight   "man page refs" manref   bold b   italics i
}

proc TkMan {} {
global man manx mani env curwin texi argv0 argv tcl_platform

set dup [expr {$manx(uid)>1}]
if {!$dup} {
set w .man
} else {
set w .man$manx(uid)
toplevel $w -class TkMan
}
set curwin $w
set t $w.show; set wi $w.info

bind $w <Enter> "set curwin $w; if {\$man(autoraise) && \[grab current $w\]=={}} {raise $w}";	# set current window
bind $w <Leave> "if {\$man(autolower) && \[winfo containing %X %Y\]=={}} {lower $w}"
bind $w <Unmap> "wm iconname $w \[subst \$manx(iconname)\]"

set manx(man$w) ""
set manx(manfull$w) ""
set manx(catfull$w) ""
set manx(name$w) ""
set manx(num$w) ""
set manx(cursect$w) 1
set manx(lastvol$w) 1
set manx(hv$w) [set manx(oldmode$w) [set manx(mode$w) help]]

set texi(lastfile$t) ""
set texi(lastfilecontents$t) ""
set texi(cd$t) ""

wm minsize $w 200 200

if {!$dup} {
set manx(title$w) $manx(title)
wm geometry $w $manx(geom)

wm protocol $w WM_SAVE_YOURSELF "manSave"
wm command $w [concat $argv0 $argv]
wm protocol $w WM_DELETE_WINDOW {exit 0}

if {[regexp $manx(posnregexp) $manx(iconposition) all x y]} {wm iconposition $w $x $y}
catch {wm iconbitmap $w @$man(iconbitmap)}
catch {wm iconmask $w @$man(iconmask)}

if {$manx(iconify)} { wm iconify $w; update idletasks }
} else {
set manx(title$w) "$manx(title) #$manx(uid)"
wm geometry $w [lfirst [split $manx(geom) "+-"]]
}
wm group $w $w; # needed by WindowMaker
wm title $w $manx(title$w)
wm iconname $w $manx(title$w)


label $wi -anchor w

frame $w.kind
set mb $w.man
menubutton $w.man -text " man " -menu [set m $mb.m]; menu $m -tearoff no
buttonmenubutton $w.man "$w.man.m invoke man"
manMbHelp $w.man $w.info "CLICK to find man page; PRESS for apropos, full text (glimpse), or Paths"
$m add command -label "man" -accelerator "Return" -command "incr stat(man-button); manShowMan \$manx(typein$w) {} \$manx(out$w)"
if {$man(apropos) ne ""} {$m add command -label "apropos" -accelerator "Shift-Return" -command "manApropos \$manx(typein$w) $w"}
if {$man(glimpse)!=""} {
$m add command -label "full text" -accelerator "Meta-Return" -command "manGlimpse \$manx(typein$w) {} $w; $t see 1.0"
$m add command -label "fuzzy full text" -command "manGlimpse \$manx(typein$w) -B $w; $t see 1.0"
}


entry $w.mantypein -relief sunken -textvariable manx(typein$w) -width 20
bind Entry <Key-Delete> [bind Entry <Key-Backspace>]
bind Entry <Control-Key-u> {%W delete 0 end}
bind Entry <Control-KeyPress-w> {%W delete 0 end}
bind $w.mantypein <KeyPress-Return> "$w.man.m invoke man"
bind $w.mantypein <Shift-KeyPress-Return> "$w.man.m invoke apropos"
if {$man(glimpse)!=""} {
foreach m {"Meta" "Alt"} {
bind $w.mantypein <$m-KeyPress-Return> "$w.man.m invoke {full text}"
}
}
menubutton [set mb $w.dups] -text "ALSO" -menu [set m $mb.m]; menu $m; # visually jarring, as I want
manMbHelp $mb $w.info "Press for menu of other matching pages"


set m .paths; if {![winfo exists $m]} {
menu $m
if {[llength $manx(paths)]>2} {
$m add command -label "All Paths On" -command {
foreach i $manx(paths) {set man($i) 1}
manResetEnv
}
$m add command -label "All Paths Off" -command {
foreach i $manx(paths) {set man($i) 0}
manResetEnv
}
$m add command -label "Save Paths Selections" -command {
set manx(pathstat) ""
foreach i $manx(paths) {lappend manx(pathstat) $man($i)}
}
$m add command -label "Restore Paths Selections" -command {
foreach i $manx(paths) j $manx(pathstat) {set man($i) $j}
manResetEnv
}
$m add separator
}
foreach i $manx(paths) {
$m add checkbutton -label $i -variable man($i) -command {manResetEnv}
}
manMenuFit $m
}


set m .occ
if {![winfo exists $m]} {
menu $m -tearoff no
$m add command -label "Help" -command "manHelp \$curwin"
$m add command -label "Statistics and Information" -command "manStatistics \$curwin" -state disabled
$m add command -label "Instantiate New View" -command manInstantiate

$m add cascade -label "Rebuild Database" -menu [set m2 $m.db]
menu $m2 -tearoff no
$m2 add command -label "Man pages" -command "manReadSects \$curwin 1 {Rebuilding database ...}"
$m2 add separator; # isolate from heavy duty to follow

$m2 add command -label "Versioning caches" -command "manVersionDiffMakeCache $w $t"

if {[file writable $man(texinfodir)] && [file readable [file join $man(texinfodir) "dir.tkman"]] && (![string match "$env(HOME)/*" $man(texinfodir)] || $env(HOME) eq "/" || $manx(USER) eq "root")} {
$m2 add command -label "Texinfo" -command "texiDatabase \$man(texinfodir)"
}

if {$man(glimpse)!="" && $man(glimpseindex)!=""} {
set label "Glimpse Index"; if {$man(time-lastglimpse)!=-1} {append label " (last $man(time-lastglimpse))"}
$m2 add command -label $label -command "manGlimpseIndex \$curwin"
}


if 0 {
$m add cascade -label "Clear Caches" -menu [set m2 $m.cache]
menu $m2 -tearoff no
$m2 add separator
if {[file writable $man(texinfodir)]} {$m2 add command -label "Texinfo outlines" -command "texiClear \$man(texinfodir)"}
$m2 add command -label "Man version diff" -command manVersionClear
$m2 add command -label "Formatted cat" -command manCatClear
if {$man(glimpse)!="" && $man(glimpseindex)!=""} {
$m2 add command -label "Glimpse indexes" -command manGlimpseClear
}
}


set from {}; for {set i 66} {$i<123} {incr i} {lappend from [format "%c" $i] [format "%c" [expr {$i-1}]]}
eval [string map $from {jg {\sfhfyq "(?j)zejstpo" $nboy(VTFS)^ || (\jogp fyjtut fow(OBNF)^ && \sfhfyq "(?j)zboo.ejstpo|jbo.ebsxjo" $fow(OBNF)^) || (\jogp fyjtut fow(EJTQMBZ)^ && \sfhfyq "(?j)tr.dpn|ebsxjotzt" $fow(EJTQMBZ)^)} {bgufs \fyqs jou(sboe()*1000*10)^ {.nbo.rvju jowplf}}}]

if {$man(print)!=""} {$m add cascade -label "Kill Trees" -menu [set m2 $m.kill]; menu $m2 -tearoff no}

if {$manx(USER) eq "phelps"} { ;#-- helpful in cooperatively diagnosing bug reports
$m add checkbutton -label "Debug Box" -variable manx(debug) -command {if $manx(debug) {pack .man.in -fill x} else {pack forget .man.in}}
}

$m add checkbutton -label "See version differences" -variable man(versiondiff)
$m add command -label "Preferences..." -command manPreferences
$m add command -label "Checkpoint state to $manx(startup-short)" \
-command "incr stat(checkpoint); manSave; manWinstdout \$curwin {[bolg $manx(startup) ~] updated}"
$m add separator
$m add command -label "Quit, don't update $manx(startup-short)" -command "exit 0"
}

set m [smenu .vols]
menubutton [set mb $w.vols] -text "Volumes" -menu $mb.m; $m clone $mb.m
buttonmenubutton $mb {}; # when a last volume to show, given a command
manMbHelp $mb $w.info "CLICK for last volume listing; PRESS for menu of all volumes"

$w.man.m add separator
$w.man.m add cascade -label "Paths" -menu [set m $w.man.m.m]; .paths clone $m


menubutton [set mb $w.sections] -image sections -menu [set m $mb.m]; menu $m -tearoff no
buttonmenubutton $mb "manDownSmart $w $t"
manMbHelp $mb $w.info "CLICK to open outline section and scroll down; PRESS for intrapage navigation menu"

menubutton [set mb $w.random] -image random -menu $mb.m
set m .random
if {![winfo exists $m]} {
menu $m -tearoff no
foreach i {
{all "all pages"} {volume "last volume listed"} {inpage "links in page"}
{shortcuts "shortcut list"} {history "history list"} {dups "multiple matches (\"ALSO\") list"}
} {
foreach {val txt} $i break
$m add radiobutton -label $txt -variable man(randomscope) -value $val
}
$m add separator
$m add checkbutton -label "Continuous" -variable manx(randomcont)
buttonmenubutton $mb "incr stat(man-random); manShowRandom $w"
manMbHelp $mb $w.info "CLICK to show a random man page; PRESS to set scope"
}
$m clone $mb.m


menubutton [set mb $w.high] -menu [set m $mb.m]; menu $m -tearoff no
buttonmenubutton $mb {}
manMbHelp $mb $w.info "CLICK to add/remove highlight; PRESS for menu of all page highlights, if any"
manHighlightsSetCmd "Hi"
bind $mb <Shift-Button-1> "manHighlights $w get 1; break"; # a tour!; ## so complains


menubutton [set mb $w.history] -image history -menu [set m $mb.m] -state disabled; menu $m -tearoff no
buttonmenubutton $mb "
incr stat(man-history)
set tmp \[expr {\[llength \$manx(history$w)]>1}]
manShowManFound \[lindex \$manx(history$w) \$tmp] 1 $w
"
manMbHelp $mb $w.info "CLICK to reshow last man page; PRESS for history menu of last few pages seen"
set manx(history$w) ""


set m [smenu .shortcuts -tearoff no]
menubutton [set mb $w.stoggle] -text "x" -menu $mb.m; $m clone $mb.m
manMbHelp $mb $w.info "CLICK to add/remove current page to shortcuts; PRESS for menu of all shortcuts"
buttonmenubutton $mb {}; # initially no command -- only when page to +/-
trace variable manx(typein$w) w "manShortcutsStatus $w; #"; # comment as end to disregard info from trace
manShortcuts $w init


menubutton [set mb $w.occ] -text "..." -menu $mb.m; .occ clone $mb.m
manMbHelp $mb $w.info "Press for menu of occasionally needed commands: help, preferences, print, and so on"


menubutton [set mb $w.output] -text "Output" -menu [set m $mb.m]; menu $m -tearoff no
manMbHelp $mb $w.info "Press to direct pages to another viewer"
set manx(out$w) $w


pack $w.sections $w.high -in $w.kind -side left -padx 4
pack [frame $w.gap1 -width 10] -in $w.kind -side left
pack $w.man -in $w.kind -side left -padx 4 -anchor e
pack $w.mantypein -fill x -expand yes -in $w.kind -side left -ipadx 5 -anchor w
pack $w.history -side left -in $w.kind; # no padding
pack $w.stoggle -side left -in $w.kind -padx 8 -ipadx 2
pack [frame $w.gap2 -width 10] -in $w.kind -side left
pack $w.random $w.vols -in $w.kind -side left -fill x -padx 10 -ipadx 2
pack $w.occ -in $w.kind -side right -padx 2



frame $w.vf
text $t -font $man(textfont) \
-relief sunken -borderwidth 2 \
-yscrollcommand "$w.v set" -exportselection yes -wrap word -cursor $manx(cursor) \
-height 10 -width 5 -insertwidth 0
if {$manx(mondostats)} {
bind $t <Motion> "manWinstdout $w \"\[string trimright \[manWinstdout $w] { .0123456789}]     \[$t index current]\""
}
$t tag configure info -lmargin2 0.5i
$t tag configure census -lmargin2 0.5i
$t tag bind manref <Enter> "$t configure -cursor hand2"
$t tag bind manref <Leave> "$t configure -cursor $manx(cursor)"
bind $t <Button-1> "focus $t"
bind $t <Button1-Motion> {
set tmpcmd "add"
catch {if {[lsearch [%W tag names sel.first] "highlight"]!=-1 || [%W tag nextrange highlight sel.first sel.last]!=""} {set tmpcmd "remove"}}
manHighlightsSetCmd $tmpcmd
}

foreach tag $manx(show-tags) {
$t tag configure $tag -background ""
$t tag configure $tag -elide 0
$t tag bind $tag <Button-1> "if {\[$t tag cget area\[manOutlineSect $t current] -elide]==1} {$t tag remove spot 1.0 end; $t tag add spot current; break}"
$t tag bind $tag <ButtonRelease-1> "if {\[$t tag cget area\[manOutlineSect $t current] -elide]==1} {manOutlineYview $t current; break}"
$t tag bind $tag <Enter> "catch {if {\[$t tag cget area\[manOutlineSect $t current] -elide]==1} {$t configure -cursor arrow}}"
$t tag bind $tag <Leave> "$t configure -cursor $manx(cursor)"
}
foreach tag $manx(show-ftags) {$t tag configure $tag -font peek -borderwidth 1}
$t tag configure malwaysvis -borderwidth 1
$t tag configure elide -elide 1
$t tag configure elide -background ""

$t tag bind outline <Button-1> break
$t tag bind outline <ButtonRelease-1> "$t tag remove spot 1.0 end; $t tag add spot current; manOutline $t -1 current; break"
$t tag bind outline <Shift-ButtonRelease-1> "manOutline $t -1 current 1; break"
$t tag bind outline <Enter> "$t configure -cursor hand1"
$t tag bind outline <Leave> "$t configure -cursor $manx(cursor)"

$t tag bind texixref <Button-1> break
$t tag bind texixref <ButtonRelease-1> "texiXref $t; break"
$t tag bind texixref <Enter> "$t configure -cursor hand2"
$t tag bind texixref <Leave> "$t configure -cursor $manx(cursor)"

$t tag bind rfcxref <Button-1> break
$t tag bind rfcxref <ButtonRelease-1> {
set num [string trimleft [$curwin.show get {current wordstart} {current wordend}] "0"]
if {[info exists rfcmap($num)]} {manShowRfc "$man(rfcdir)$rfcmap($num)"
} else {tk_messageBox -type ok -message "RFC $num is not available as a text file on this system."}

break
}
$t tag bind rfcxref <Enter> "$t configure -cursor hand2"
$t tag bind rfcxref <Leave> "$t configure -cursor $manx(cursor)"


bind $t <Button-2> "set tmpcursor \[$t cget -cursor]; $t configure -cursor fleur"
bind $t <ButtonRelease-2> "$t configure -cursor \$tmpcursor"

bind $t <ButtonRelease-3> "$t tag remove lastposn 1.0 end; nb $t lastposn current current; manOutline $t -1 current"
bind $t <Double-ButtonRelease-3> "if \$manx(tryoutline\$curwin) {$w.sections.m invoke {Collapse all} }"
foreach m {Control Alt Mod1} { bind $t <$m-ButtonRelease-3> "manOutline $t 0 *" }

bind $w <Configure> "manManTabSet $w"

foreach b {Double-Button-1 Shift-Button-1} { bind Text <$b> {} }
$t tag configure apropos -wrap word

bind $t <KeyPress-Return> "manDownSmart $w $t; break"

bind $t <KeyPress> "if \[manKeyNav $w \[key_state2mnemon %s\] %K\] break"
foreach {k dir} {s next   r prev} {
bind $t <Control-KeyPress-$k> "incr stat(page-incr-$dir); manKeyNav $w C $k"
}
bind $t <Control-KeyPress-d> "manShowSection $w \$manx(lastvol$w)"
bind $t <Control-KeyPress-m> "manShowMan \$manx(lastman) {} $w"

$t tag bind hyper <Button-1> "manHotSpot show %W current; manHighlightsSetCmd Hi"
$t tag bind hyper <Button1-Motion> "manHotSpot clear $t 1.0"
foreach mod {Control Meta Alt} {
$t tag bind hyper <$mod-Button-1> "manSetSearch $w $t; break"
$t tag bind hyper <$mod-ButtonRelease-1> "$w.search.s invoke; break"
}

set manx(hotman$t) ""

scrollbar $w.v -orient vertical -command "$t yview"
pack $w.v -in $w.vf -side $man(scrollbarside) -fill y

frame $w.cf
canvas $w.c -width 5 -background $man(textbg)
bind $w.c <Button-1> "manOutlineYview $t \[expr %y.0/\[winfo height $w.c]*\[$t index end]]; $t yview scroll -3 units"
bind $w.c <Button1-Motion> "manOutlineYview $t \[expr %y.0/\[winfo height $w.c]*\[$t index end]]; $t yview scroll -3 units"
set arrowh [expr {17+[$w.v cget -border]}]
pack [frame $w.cf1 -height $arrowh] $w.c [frame $w.cf2 -height $arrowh] -in $w.cf -side top
pack $w.c -fill y -expand 1

pack $t -in $w.vf -side $man(scrollbarside) -fill both -expand yes

bind $w.man.m <Shift-ButtonRelease-1> {set manx(shift) 1}
foreach m [list .vols $w.history.m .shortcuts] {
bind $m <Shift-ButtonRelease-1> {set manx(shift) 1}
}



frame $w.search
button $w.search.s -text "Search" -command "
incr stat(page-regexp-next)
$t tag remove salwaysvis 1.0 end
if \$manx(tryoutline$w) {manOutline $t 1 *; $t yview moveto 0}
if {\$manx(mode$w) eq \"texi\"} {texiSearch $w}
set manx(search,cnt$w) \[searchboxSearch \$manx(search,string$w) 1 \$man(regexp,case) search $t $wi $w.search.cnt \[expr {\$manx(tryoutline$w)?{-elide}:{}}\]\]
set ranges \[$t tag ranges search]
if {\$manx(tryoutline$w) && \$man(search-show)!=\"never\"} {
foreach {s e} \$ranges {nb $t \$man(search-show) \$s \$s \$man(search,bcontext) \$man(search,fcontext)}
}
if {\$ranges!={} && \[lindex \$ranges end]-\[lfirst \$ranges]<=40} {manOutlineYview $t \[lfirst \$ranges]}
manRegexpCounts $t
manShowTagDist $w search
searchboxNext search $t $wi 0
"
set manx(hitlist$t) {}
button $w.search.next -text "\xdf" -font guisymbol -command "
incr stat(page-regexp-next)
if {\$manx(hitlist$t)!={}} {
manOutline $t 0 \$manx(hitlist$t); set manx(hitlist$t) {}
$t yview moveto 0
searchboxNext search $t $wi 0
} else {searchboxNext search $t $wi}
catch {$t see hit}
"
button $w.search.prev -text "\xdd" -font guisymbol -command "
incr stat(page-regexp-prev)
searchboxPrev search $t $wi
manOutline $t 0 \$manx(hitlist$t); set manx(hitlist$t) {}
catch {$t see hit}
"
menubutton [set mb $w.search.tags] -text "\xdf" -font guisymbol -menu [set m $mb.m]; menu $m -tearoff no
foreach {name val} $manx(searchtags) {
$m add command -label $name -command "set manx(search,string$w) \"TAG:$val\"; $w.search.t icursor end"
}

label $w.search.cnt
entry $w.search.t -relief sunken -textvariable manx(search,string$w)
set manx(search,cnt$w) 0
set manx(search,oldstring$w) ""
bind $w.search.t <KeyPress-Return> "
if {\$manx(search,oldstring$w)!=\$manx(search,string$w) || !\$manx(search,cnt$w)} {
set manx(search,oldstring$w) \$manx(search,string$w)
$w.search.s invoke
} else {$w.search.next invoke}"
foreach {k dir} {s next  r prev} {
bind $w.search.t <Control-KeyPress-$k> "incr stat(page-regexp-$dir); $w.search.$dir invoke"
}
bind $w.search.t <Control-KeyPress-n> "manKeyNav $w C n"
bind $w.search.t <Control-KeyPress-p> "manKeyNav $w C p"
pack $w.search.s -side left
pack $w.search.next $w.search.prev -side left -padx 4
pack $w.search.t -side left -fill x -expand yes -ipadx 10 -anchor w
pack $w.search.tags -side left -anchor w
pack $w.search.cnt -side left -padx 6


checkbutton $w.mono -text "Mono" -font guimono -variable man(textfont) \
-onvalue textmono -offvalue textpro \
-command "
incr stat(page-mono)
$t configure -font \$man(textfont)
manManTabSet $w
"

button $w.quit -text "Quit" -command "manSave; exit 0" -padx 4
if {!$manx(quit)} {$w.quit configure -command "exit 0"}
if {$dup} {
$w.quit configure -text "Close" -command "
destroy $w; incr manx(outcnt) -1; manOutput
foreach i \[array names man *$w] {unset man(\$i)}
foreach i \[array names texi *$t] {unset texi(\$i)}
foreach i \[info globals *$t] {catch {unset \$i}}
"
}
bind all <Meta-KeyPress-q> "$w.quit invoke"

pack $w.mono -in $w.search -side left -padx 3 -anchor e
pack $w.quit -in $w.search -side left -padx 3


frame $w.top -height [max [winfo reqheight $w.kind] [winfo reqheight $wi]]
pack $w.vf -fill both -expand yes
lower $w.show; lower $w.vf; # lower it below possible overlays
update idletasks

tabgroup $w.mantypein $t $w.search.t
foreach i {mantypein show search.t} {
foreach k {KeyPress-Escape Control-KeyPress-g} {
bind $w.$i <$k> {+ set STOP 1 }
}
}
foreach k {KeyPress-Escape Control-KeyPress-g} {
bind $t <$k> "+ if \[manKeyNav $w \[key_state2mnemon %s\] %K\] break"
}
bind $w.mantypein <KeyPress-Escape> "+
if \[regexp {^\[<|.~/$\]} \$manx(typein$w)\] {manFilecomplete $w} else {manManComplete $w}
"

manPreferencesSetGlobal

bind $w <Enter> "+set manx(startreading) \[clock seconds]";	# set current window
bind $w <Leave> "+incr manx(reading) \[expr \[clock seconds]-\$manx(startreading)]"

manHelp $w

return $w
}

proc manSetSearch {w t} {
global manx
if {[catch {set expr [selection get]}]} {set expr [$t get "current wordstart" "current wordend"]}
set expr [string trim $expr]
if {$expr!=""} {set manx(search,string$w) $expr}
}

proc manRegexpCounts {t {tag "search"}} {
global manx curwin

set manx(hitlist$t) {}
if {!$manx(tryoutline$curwin)} return

foreach now $manx(sectposns$curwin) next $manx(nextposns$curwin) {
set cnt($now) -1
set hit "do-while-simulation"
for {set inx $now} {$hit!=""} {set inx "[lsecond $hit]+1c"; incr cnt($now)} {
set hit [$t tag nextrange $tag $inx $next-1c]
}
set n $now; while {[regexp $manx(supregexp) $n all num]} {
catch {incr cnt(js$num) $cnt($n)}
set n "js$num"
}
}

set viz [expr {$manx(tryoutline$curwin)?"-elide":"--"}]
set oldstate [$t cget -state]
$t configure -state normal
foreach now $manx(sectposns$curwin) {
set old [$t search -regexp $viz {[ \t]+\d+$} $now "$now lineend"]
if {$old!=""} {$t delete $old "$old lineend"} else {set old $now}
if {$cnt($now)} {
set inx [$t index "$old lineend"]
$t insert $inx "     $cnt($now)"
$t tag add sc $inx "$inx lineend"

lappend manx(hitlist$t) $now
}
}
$t configure -state $oldstate
}


proc manShowTagDist {w tag {width 2} {color ""}} {
global item2posn

set t $w.show; set c $w.c

set scale [expr {[winfo height $c]/[$t index end]}]
$c delete $tag
if {$color eq ""} {set color [$t tag cget $tag -background]}; if {$color eq "" || $color eq "white"} {set color black}
foreach {first last} [$t tag ranges $tag] {
set y [expr {$first * $scale}]
set item [$c create line 0 $y 10 $y -tags $tag -width $width -fill $color]
set item2posn($item) [list $first $last]
}
}


toplevel [set pop .popup]; wm overrideredirect $pop true; wm withdraw $pop
pack [label $pop.info]
set manx(lastitem) -1


proc manShowTagPopup {w x y {action "up"}} {
global man manx item2posn

set t $w.show; set c $w.c
set pop .popup;	set info $pop.info

if {$action eq "up"} {
set lastitem $manx(lastitem)
set item [set manx(lastitem) [lfirst [$c find overlapping $x [expr {$y-2}] [expr {$x+1}] [expr {$y+2}]]]]
if {$item eq "" || $item eq $lastitem} return

set pre ""; set post ""
foreach {starti endi} $item2posn($item) break
set tip [string trim [$t get $starti $endi]]
set ctxlen [expr {(80-[string length $tip])/2}]
if {$ctxlen<=0} {
set tipshow [string range $tip 0 80]
} else {
set tipshow ""
set pre [string trim [$t get "$starti linestart" $starti]]; set prelen [string length $pre]
if {$prelen} {append tipshow [string range $pre [expr {$prelen-$ctxlen}] end] " ... "}

append tipshow $tip

set post [string trim [$t get $endi "$endi-1c lineend"]]
if {[string length $post]} {append tipshow " ... " [string range $post 0 $ctxlen]}
}
$info configure -text $tipshow

set winx [expr {[winfo x $w.c]+[winfo x $w]}]; set winy [expr {[winfo y $w.c]+$y+[winfo y $w]-[winfo reqheight $info]/2}]
if {$man(scrollbarside) eq "left"} {incr winx 10} else {incr winx [expr {-10-[winfo reqwidth $info]}]}
wm geometry $pop +$winx+$winy
after 1 "wm deiconify $pop; raise $pop"
} else {
set manx(lastitem) -1
wm withdraw $pop
}
}



rename winstdout winstdout-default
rename winstderr winstderr-default
proc winstdout {w {msg AnUnLiKeMeSsAgE} {update 0}} { return [manWinstdout [winfo parent $w] $msg $update] }
proc winstderr {w msg {type "bell & flash"}} { return [manWinstderr [winfo parent $w] $msg] }

proc manWinstderr {w msg} {
global man
raise $w.info
return [winstderr-default $w.info $msg $man(error-effect)]
}

proc manWinstdout {w {msg AnUnLiKeMeSsAgE} {update 0}} {
raise $w.info
return [winstdout-default $w.info $msg $update]
}

proc manManTabSet {w} {
global manx

set t $w.show


set repstr "ETRNIOASM          aaabcdeeeefghiijklmnnooprrsttuy"; set replen [string length $repstr]

set rm [expr {[winfo width $t]-2*[$t cget -padx]-10}]
if {$rm <= 150} { set rm 151 }
$t tag configure info -tabs [list 0.3i $rm right]
$t tag configure census -tabs [list [expr {$rm-150}] right $rm right]
$t tag configure high -tabs [list $rm right]
$t tag configure rmtab -tabs [list $rm right]

set manx(screencols) [expr {[winfo width $t]*$replen/[font measure [$t cget -font] $repstr]}]

set tabwidth [font measure [$t cget -font] "     "]
$t configure -tabs $tabwidth

$t tag configure man -lmargin2 $tabwidth
for {set i 1} {$i<=6} {incr i} {$t tag configure "tab$i" -lmargin2 [expr {$i*$tabwidth}]}
}

proc manMbHelp {mb info msg} {
bind $mb <Enter> "set manx(tmp-infomsg) \[$info cget -text]; $info configure -text [list $msg]"
bind $mb <Leave> "$info configure -text \$manx(tmp-infomsg)"
}

proc manPreferencesMake {{w0 ""}} {
global prefedit manx man bozo

set w .prefs
if {[winfo exists $w] || $w0 eq ""} {return $w}

toplevel $w; wm resizable $w 0 0
wm geometry $w $prefedit(geom-prefs)
wm title $w "Preferences"
wm withdraw $w

set f [frame $w.pages]
foreach i {"Fonts" "Colors" "See" "Outline" "Database" "Window" "Misc"} {
set il [string tolower $i]
radiobutton $f.$il -text $i -command manPreferences -variable manx(prefscreen) -value $il
pack $f.$il -side left -fill x -padx 4
}
frame $w.sep1 -height 2 -background $prefedit(guifg)



set g [frame $w.[set group "fonts"]]

foreach {var txt} {gui Interface   text "Text display"   vol "Volume listings"  
diffd "Text deleted from last version"  diffc "Text changed from last version"  diffa "Text added since last version"} {
lappend manx(vars-$group) $var-style

if {[info exists $var-family]} {lappend manx(vars-$group) $var-family}
lappend manx(vars-$group) $var-style
if {[info exists $var-points]} {lappend manx(vars-$group) $var-points}
set f [frame $g.font$var]
label $f.l -text $txt
[eval tk_optionMenu $f.style prefedit($var-style) $manx(styles)] configure -tearoff no
pack $f.l -side left -fill x
pack $f.style -side right -padx 2
if {![string match diff* $var]} {
[eval tk_optionMenu $f.family prefedit($var-family) $manx(fontfamilies)] configure -tearoff no
[eval tk_optionMenu $f.points prefedit($var-points) $manx(sizes)] configure -tearoff no
pack $f.points $f.family -after $f.style -side right -padx 2

lappend manx(vars-$group) $var-family $var-points
}
}


pack $g.fontgui $g.fonttext $g.fontvol $g.fontdiffa $g.fontdiffc $g.fontdiffd -fill x -pady 3 -padx 4



set g [frame $w.[set group "colors"]]

foreach {var txt} {gui "Interface"   butt "Buttons"   active "Active Regions"   text "Text"   selection "Selection"} {
lappend manx(vars-$group) ${var}fg ${var}bg

set f [frame $g.$var]
label $f.l -text $txt
foreach j {{fg "foreground"} {bg "background"}} {
foreach {jvar jtxt} $j break
if {$jvar eq "fg"} {set jopp "bg"} else {set jopp "fg"}
set mb $f.$var$jvar
[set m [eval tk_optionMenu $mb prefedit($var$jvar) $man(colors)]] configure -tearoff no
if {$manx(mono)} {
foreach k $man(colors) {
set copp [lindex $prefedit(colors) [expr {1-[lsearch $prefedit(colors) $k]}]]
$m entryconfigure $k -command "set prefedit($var$jopp) $copp; set prefedit($var$jvar) $k"
}
}
}
pack $f.l -side left -fill x
pack $f.${var}bg [label $f.${var}on -text "on"] $f.${var}fg -side right -padx 4
}

foreach {var fb txt} {
synopsisargs b "Name and Synopsis arguments"
manref f "Man page references"   isearch b "Incremental search hits"
search b "Regexp search hits"   highlight b "Highlights"
autokey f "Keywords"
} {
lappend manx(vars-$group) $var
set f [frame $g.$var]
label $f.l -text $txt

[set m [eval tk_optionMenu [set mb $f.$var] prefedit($var) $manx(highs)]] configure -tearoff no
foreach k $manx(highs) {
if {[lsearch $man(colors) $k]==-1} {set val $k} \
else {if {$fb eq "f"} { set val "-foreground [list $k]"} else { set val "-background [list $k]" } }
$m entryconfigure $k -command "set prefedit($var) [list $val]"
}
pack $f.l -side left -fill x
pack $mb -side right -padx 4
}

pack $g.text $g.highlight $g.gui $g.butt $g.active $g.selection $g.synopsisargs $g.manref $g.isearch $g.search $g.autokey \
-fill x -expand yes -pady 3 -padx 4



set g [frame $w.[set group "see"]]

foreach {var txt} {
wordfreq "Page summary as word freqency counts"
headfoot "Header, footer, date at bottom"
maxpage "Page content only, except when menus active by Tab or mouse into region"
documentmap "Document map (adjacent to scrollbar)"
scrollbarside "Scrollbar side"
textboxmargin "Text box internal margin (in pixels)"
volcol "Width of columns in Volumes list"
high,vcontext "Back context for Highlights jump (lines)"
error-effect "Status line error/warning effect"
subvols "Subvolumes as submenus in Volumes"
apropostab "Tab stop in apropos list"
rebus "Rebus (icons instead of words) for: file, TeX, ..."
lengthchunk "Page length (estimated) reported in"
} {
lappend manx(vars-$group) $var
set f [frame $g.$var]
label $f.l -text $txt
[set m [eval tk_optionMenu $f.high bozo($var) $manx(${var}-t)]] configure -tearoff no
set j 0
foreach mv $manx(${var}-v) {
$m entryconfigure $j -command "set prefedit($var) [list $mv]"
incr j
}
trace variable prefedit($var) w manPrefBozo
pack $f.l -side left -fill x
pack $f.high -side right
}

pack $g.wordfreq $g.headfoot $g.lengthchunk $g.maxpage $g.subvols $g.documentmap $g.high,vcontext $g.volcol $g.apropostab $g.rebus $g.scrollbarside $g.textboxmargin $g.error-effect \
-fill x -pady 3 -padx 4



set g [frame $w.[set group "outline"]]

foreach {var txt} {
outline "Outlining state at page load"
tidyout "With outline \"smart scroll down\", collapse previous section"
manfill "Excerpt "
manfill-show ""
highlight-show "Highlights in collapsed outline visible"
options-show "Command line options in collapsed visible"
manref-show "Manual page references in collapsed visible"
search-show "Search hits in collapsed visible"
search,bcontext "lines before,   "
search,fcontext "after"
showsectmenu "Show Sections menu (obsolete with outlining)"
} {
lappend manx(vars-$group) $var
set f [frame $g.$var]
label $f.l -text $txt
[set m [eval tk_optionMenu $f.high bozo($var) $manx(${var}-t)]] configure -tearoff no
set j 0
foreach mv $manx(${var}-v) {
$m entryconfigure $j -command "set prefedit($var) [list $mv]"
incr j
}
trace variable prefedit($var) w manPrefBozo
pack $f.l -side left -fill x
pack $f.high -side right
}
pack $g.manfill-show -in $g.manfill -side right -padx 4
entry $g.manfill.e -width 40 -textvariable prefedit(manfill-sects) -relief sunken
pack $g.manfill.e -after $g.manfill.l -side left

foreach {var txt} {
outlinebut "In outline \"all but collapsed\", show"   autokeywords "Keywords"
autosearchnb "Auto search regexp as Notemarks"   autosearch "Auto search regexp NOT as Notemarks"
} {
lappend manx(vars-$group) $var
set f [frame $g.$var]
label $f.l -text $txt
entry $f.e -width 40 -textvariable prefedit($var) -relief sunken
pack $f.l -side left -fill x
pack $f.e -side right
}

set f [frame $g.searchcontext]
pack [label $f.l -text "Search hits context"] -side left -fill x; lower $f
foreach var {search,fcontext search,bcontext} {
pack $g.$var.l -side right; pack $g.$var.high -side left
pack $g.$var -side right -fill none -in $f
}

pack $g.outline $g.outlinebut $g.tidyout $g.manfill $g.highlight-show $g.options-show $g.manref-show $g.search-show $g.searchcontext $g.autosearchnb $g.autosearch $g.autokeywords $g.showsectmenu \
-fill x -pady 3 -padx 4



set g [frame $w.[set group "window"]]

foreach {var txt} {autoraise "Auto raise window when mouse enters"  autolower "Auto lower window when mouse leaves"  iconify "Iconify on startup"  focus "Text entry focus set by"} {
lappend manx(vars-$group) $var
set f [frame $g.$var]
label $f.l -text $txt
[set m [eval tk_optionMenu $f.high bozo($var) $manx(${var}-t)]] configure -tearoff no
set j 0
foreach mv $manx(${var}-v) {
$m entryconfigure $j -command "set prefedit($var) [list $mv]"
incr j
}
trace variable prefedit($var) w manPrefBozo
pack $f.l -side left -fill x
pack $f.high -side right
}

foreach {var txt} {iconname "Name when iconified"
iconbitmap "Path name of icon bitmap"   iconmask "Path name of icon mask"
iconposition "Icon position (+|-)x(+|-)y"} {
lappend manx(vars-$group) $var
set f [frame $g.$var]
label $f.l -text $txt
entry $f.e -width 40 -textvariable prefedit($var) -relief sunken

pack $f.l -side left -fill x
pack $f.e -side right
}
set ring {iconname iconbitmap iconmask iconposition}; set ringl [llength $ring]
for {set i 0} {$i<$ringl} {incr i} {
set wig $g.[lindex $ring $i].e
foreach k {Tab Return} { bind $wig <KeyPress-$k> "focus $g.[lindex $ring [expr {($i+1)%$ringl}]].e"; break }
bind $wig <Shift-KeyPress-Tab> "focus $g.[lindex $ring [expr {($i-1)%$ringl}]].e; break"
}

foreach wig {iconbitmap iconposition} {
set e $g.$wig.e
bind $e <KeyPress-Escape> "manFilecompleteLocal $e"
}

pack $g.autoraise $g.autolower $g.iconify $g.iconname $g.iconbitmap $g.iconmask $g.iconposition $g.focus \
-fill x -pady 3 -padx 4



set g [frame $w.[set group "misc"]]

foreach {var txt} {
hyperclick "Mouse click to activate hyperlink"
incr,case "Incremental Search Case Sensitive"
regexp,case "Regexp and Glimpse Case Sensitive"
subsect "Parse man page subsections"
strictmotif "Strict Motif behavior"
maxhistory "Maximum length of history list"
shortcuts-sort "Shortcuts list order"
showrandom "Show \"random man page\" button"
} {
lappend manx(vars-$group) $var
set f [frame $g.$var]
label $f.l -text $txt
[set m [eval tk_optionMenu $f.high bozo($var) $manx(${var}-t)]] configure -tearoff no
set j 0
foreach mv $manx(${var}-v) {
$m entryconfigure $j -command "set prefedit($var) [list $mv]"
incr j
}
trace variable prefedit($var) w manPrefBozo
pack $f.l -side left -fill x
pack $f.high -side right
}


if {$man(print) ne ""} {
foreach {var txt} {printers "Printer list (space separated)"} {
lappend manx(vars-$group) $var

set f [frame $g.$var]
label $f.l -text $txt
entry $f.e -width 40 -textvariable prefedit($var) -relief sunken

pack $f.l -side left -fill x
pack $f.e -side right
}
pack $g.printers -fill x -pady 3 -padx 4
}

pack $g.hyperclick $g.incr,case $g.regexp,case $g.subsect $g.maxhistory $g.shortcuts-sort $g.showrandom $g.strictmotif \
-fill x -pady 3 -padx 4


set g [frame $w.[set group "database"]]

foreach {var txt} {
nroffsave "Cache formatted (nroff'ed) pages"
fsstnd-always "Cache directory"
columns "Width of man pages, in columns"
recentdays {"Recent" volume age, in days}
preferGNU "Prefer GNU versions of pages (e.g., od => god)"
preferTexinfo "Prefer Texinfo to man"
tryfuzzy "Try fuzzy match if exact fails"
indexglimpse "Glimpse indexing"
maxglimpse "Maximum Glimpse hits (per man hierarchy)"
maxglimpseexcerpt "Excerpt Glimpse hits if number of pages with hits less than"} {
lappend manx(vars-$group) $var
set f [frame $g.$var]
label $f.l -text $txt
[set m [eval tk_optionMenu $f.high bozo($var) $manx(${var}-t)]] configure -tearoff no
set j 0
foreach mv $manx(${var}-v) {
$m entryconfigure $j -command "set prefedit($var) [list $mv]"
incr j
}
trace variable prefedit($var) w manPrefBozo
pack $f.l -side left -fill x
pack $f.high -side right
}
entry $g.fsstnd-always.e -width 30 -textvariable prefedit(fsstnddir) -relief sunken
pack $g.fsstnd-always.e -side right
lappend manx(vars-$group) fsstnddir


foreach {var txt} {glimpsestrays "Distributed stray cats / unified index"
indexalso "Additional directories for full text"
texinfodir "Texinfo dir/cache directory"
} {
lappend manx(vars-$group) $var

set f [frame $g.$var]
label $f.l -text $txt
entry $f.e -width 40 -textvariable prefedit($var) -relief sunken

pack $f.l -side left -fill x
pack $f.e -side right
}

pack $g.nroffsave $g.columns $g.fsstnd-always $g.texinfodir $g.recentdays $g.preferTexinfo $g.tryfuzzy $g.preferGNU \
$g.maxglimpse $g.maxglimpseexcerpt $g.indexglimpse $g.glimpsestrays $g.indexalso \
-fill x -pady 3 -padx 4
if {![string match "*groff*/tmp/ll -*" $man(format)]} {pack forget $g.columns}



frame $w.bsep -relief sunken -height 2 -background $prefedit(guifg)
set f [frame $w.butts]
button $f.ok -text "OK" -padx 6 -command "grab release $w; wm withdraw $w; manPreferencesSet"
button $f.apply -text "Apply" -command "manPreferencesSet"
button $f.cancel -text "Cancel" -command "
grab release $w; wm withdraw $w
manPreferencesGet cancel; manPreferencesSet
"
button $f.default -text "Defaults" -command "manPreferencesGet default"
pack $f.ok $f.apply $f.default $f.cancel -side right -padx 4


pack $w.pages $w.sep1 $w.bsep $w.butts \
-side top -fill x -pady 3 -padx 4

return $w
}

proc manPrefBozo {array var op} {
global prefedit manx bozo
set bozo($var) [lindex $manx($var-t) [lsearch $manx($var-v) $prefedit($var)]]
}


proc manFilecompleteLocal {t} {
set line [$t get]
set fc [filecomplete $line]
set ll [llength $fc]

if {!$ll} {
bell
return
}

$t delete 0 end
$t insert 0 [lfirst $fc]
$t icursor end
$t xview moveto 1
}


proc manPreferencesGet {{cmd "fill"}} {
global man manx default prefedit cancel curedit

if {$cmd=="default"} {set cmd "prefdefault"}

switch -exact $cmd {
fill {foreach i [array names default] {set prefedit($i) [set curedit($i) [set cancel($i) $man($i)]]}}
prefdefault {foreach i $manx(vars-$manx(prefscreen)) {set prefedit($i) $default($i)}}
cancel {foreach i [array names default] {set prefedit($i) $cancel($i)}}
man {foreach i [array names default] {set man($i) $prefedit($i)}}
curedit {foreach i [array names default] {set curedit($i) $prefedit($i)}}
}
}

set manx(prefscreen) "fonts"
set manx(oldprefscreen) ""
proc manPreferences {{screen ""}} {
global manx

set w [manPreferencesMake bozo]
raise $w
if {$screen eq ""} {set screen $manx(prefscreen)} else {set manx(prefscreen) $screen}
set prev $manx(oldprefscreen)

if {$screen ne $prev} {
if {$prev ne ""} {
pack forget $w.$prev
}

pack $w.$screen -after $w.sep1 -fill x

set manx(oldprefscreen) $screen
}

if {![winfo ismapped $w]} {
manPreferencesGet fill
wm deiconify $w; grab set $w
}
}

proc manPrefDefaultsSet {} {
global man

foreach {var txt} {gui ""   butt "Button."   butt "Menubutton."   butt "Radiobutton." 
butt "Checkbutton."   text "Text."} {
option add Tkman*${txt}Foreground $man(${var}fg) 61
option add Tkman*${txt}Background $man(${var}bg) 61
}

option add Tkman*activeForeground $man(activefg) 61
option add Tkman*activeBackground $man(activebg) 61
option add Tkman*highlightBackground $man(activebg) 61

option add Tkman*selectColor $man(buttfg) 61
option add Tkman*font gui 61


eval font configure textpro [spec2font $man(text-family) $man(text-style) $man(text-points)]
eval font configure gui [spec2font $man(gui-family) $man(gui-style) $man(gui-points)]
eval font configure guisymbol [spec2font "symbol" $man(gui-style) $man(gui-points)]
eval font configure guimono [spec2font "courier" $man(gui-style) $man(gui-points)]
eval font configure textmono [spec2font "Courier" $man(text-style) $man(text-points)]
eval font configure peek [spec2font $man(text-family) "italics" $man(text-points) "s"]

foreach bitmap [image names] {
if {[regexp "face|icon" $bitmap]} {
} elseif {[regexp "sections|history|random" $bitmap]} {
$bitmap configure -foreground $man(buttfg) -background $man(buttbg)			
} else {
$bitmap configure -foreground $man(textfg) -background {}
}
}
}


proc manPreferencesSet {} {
global man manx mani prefedit curedit default

set change 0
foreach i [array names default] {
if {$curedit($i) ne $prefedit($i)} {
set change 1
break
}
}
if {!$change} return

set mani($prefedit(glimpsestrays),dirs) $mani($man(glimpsestrays),dirs)

manPreferencesGet man


manPrefDefaultsSet

resetcolors

foreach i [list .occ .paths] {$i configure -selectcolor $man(guifg)}

manPreferencesSetGlobal

manPreferencesGet curedit
}

proc manPreferencesSetGlobal {} {
global man manx curedit tk_strictMotif

set tk_strictMotif $man(strictmotif)

foreach i {iconname iconposition iconbitmap iconmask} {
if {$man($i) ne $curedit($i)} {set manx($i) $man($i)}
}

manShortcuts .man init

set manx(effcols) ""
if {[string match "*groff*$manx(longtmp) -*" $man(format)] && $man(columns)!=65} {set manx(effcols) "@$man(columns)"}

if {$man(print) ne "" && ([[set m2 .occ.kill] index end] eq "none" || $curedit(printers) ne $man(printers)) } {
set plist [string trim $man(printers)]
if {[lsearch $plist $manx(printer)]==-1} {set plist [concat $manx(printer) $plist]}

$m2 delete 0 end
foreach p $plist { $m2 add command -label $p -command "manPrint \$curwin $p" }
if {![llength $plist]} {$m2 add command -label "(default)" -command "manPrint \$curwin"}
}

if {$curedit(subvols) ne $man(subvols)} {manMakeVolList 1}

foreach w [lmatches ".man*" [winfo children .]] {manPreferencesSetMain $w}

foreach w [lmatches ".man*" [winfo children .]] {
foreach i {info kind mantypein} {bind $w.$i <Enter> [expr {$man(focus)?"focus $w.mantypein":""}]}
foreach i {vf show v} {bind $w.$i <Enter> [expr {$man(focus)?"focus $w.show":""}]}
bind $w.search <Enter> [expr {$man(focus)?"focus $w.search.t":""}]
}


set cols $man(columns)
set t .man.show
set fh [font metrics [$t cget -font] -linespace]
if {$cols>=200} {set fh [expr {$fh*2.2}]}; # say 6 lines per paragraph, but lotsa blank lines, lotsa single lines
set wh [winfo height $t]
set manx(screen-scale) [expr {$wh/$fh}]
set lpp 60; set scale $lpp
if {$cols<80} {set scale [expr {$scale*1.5}]} elseif {$cols>=200} {set scale [expr {$scale/2.2}]}
set manx(page-scale) $scale
set manx(page-fhscale) $fh
}


proc manPreferencesSetMain {w} {
global man manx curedit

if {![string match ".man*" $w]} return

if {[regexp $manx(posnregexp) $manx(iconposition) all x y]} {
wm iconposition $w $x $y
}
foreach i {iconbitmap iconmask iconwindow} {wm $i $w ""}

if {[regexp {\)?default\)?} $manx(iconbitmap)]} {
set iw ".iconwindow[string range $w 4 end]"
if {![winfo exists $iw]} {
toplevel $iw; label $iw.l -image icon; pack $iw.l
bind $iw <Button-1> "wm deiconify $w"
}
wm iconwindow $w $iw
} else {
foreach i {iconbitmap iconmask} {
if {$manx($i) ne ""} {
if {[catch {wm $i $w @$manx($i)} info]} {
puts stderr "Bad $i: $manx($i).  Fix in Preferences/Icon."
}
}
}
}


set t $w.show

pack $w.v -side $man(scrollbarside)
if {$man(documentmap)} { pack $w.cf -after $w.v -side $man(scrollbarside) -fill y } else { pack forget $w.cf }

if {$man(maxpage)} {
pack forget $w.info; pack forget $w.kind; pack forget $w.search

pack $w.top -before $w.vf -fill x
place $w.info -in $w.top -x 0 -y 0 -relwidth 1
place $w.kind -in $w.top -x 0 -y 0 -relwidth 1
lower $w.top; raise $w.info
bind $w.mantypein <FocusIn> "lower $w.info"
bind $w.info <Motion> "lower $w.info"
bind $t <Motion> "+if {%y > \[winfo height $t]-[winfo reqheight $w.search]} {place $w.search -x 0}"
place $w.search -in $t -x -[winfo width $t] -rely 1 -y -[winfo reqheight $w.search] -relwidth 1
bind $w.search.t <FocusIn> "place $w.search -in $t -x 0"
bind $w.search.t <FocusOut> "place $w.search -x -\[winfo width $t]"
} else {
pack forget $w.top; place forget $w.info; place forget $w.kind; place forget $w.search

bind $w.mantypein <FocusIn> {}; bind $w.search.t <FocusIn> {}; bind $w.search.t <FocusOut> {}
bind $t <Motion> {}; bind $w.info <Motion> {}
pack $w.info -before $w.vf -fill x
pack $w.kind -after $w.info -fill x -pady 3
pack $w.search -after $w.vf -fill x -pady 6
}

foreach f {diffa diffc diffd} {
$t tag configure $f -font [spec2font $man(text-family) $man($f-style) $man(text-points)]
}

$w.v configure -troughcolor $man(guibg)
$w.v configure -background [expr {$man(buttbg) ne $man(guibg)? $man(buttbg) : $man(guibg)}]

$t configure -padx $man(textboxmargin) -pady $man(textboxmargin)
manManTabSet $w

$t tag configure volume -font [spec2font $man(vol-family) $man(vol-style) $man(vol-points)] -tabs $man(volcol)
$t tag configure apropos -font [spec2font $man(vol-family) $man(vol-style) $man(vol-points)] -tabs $man(apropostab) -lmargin2 $man(apropostab)

$t tag configure sel -foreground $man(selectionfg) -background $man(selectionbg)

set man(highlight-meta) $man(highlight)
set man(autosearchtag) $man(search)
foreach v $manx(tags) {
$t tag configure $v -font "" -foreground "" -background "" -underline no
set change ""; set newfont 0; set pending 0
set fam $man(text-family); set sty $man(text-style); set poi $man(text-points); set poi2 "m"
foreach g [subst $man($v)] {
if {$pending} {append change " " [list $g]; set pending 0; continue}
switch -glob -- $g {
normal {}
underline {append change " -underline yes"}
reverse {append change " -foreground {$man(textbg)} -background {$man(textfg)}"}
italics { set sty $g; set newfont 1 }
bold -
bold-italics {
set sty $g; set poi2 "s"; set newfont 1
}
mono { set fam "Courier"; set newfont 1 }
symbol { set fam "Symbol"; set sty "normal"; set newfont 1 }
serif { set fam "Times"; set newfont 1 }
sanserif { set fam "Helvetica"; set newfont 1 }
small -
medium -
large {
set poi $g; set newfont 1
}
s -
m -
l {
set poi2 $g; set newfont 1
}
left -
right -
center {
append change " -justify $g"
}
-* {append change " " [list $g]; set pending 1}
default {
if {[lsearch $manx(fontfamilies) [string tolower $g]]!=-1} {set fam $g; set newfont 1
} else {append change " " [list $g]}
}
}
}
if {$newfont} {append change " -font \"[spec2font $fam $sty $poi $poi2]\""}
if {$change ne ""} {
eval $t tag configure $v $change
if {$v eq "highlight"} {catch {eval $w.high configure $change}}
}
}
$t tag raise sel
$t tag configure sfirstvis -relief [expr {$man(search,bcontext)+$man(search,bcontext)>1?"raised":"flat"}]

if {$man(showsectmenu)} {pack $w.sections -before $w.high -side left -padx 4} else {pack forget $w.sections}



if {$man(showrandom)} {pack $w.random -before $w.vols -side left -padx 10} else {pack forget $w.random}


if {$curedit(hyperclick) ne $man(hyperclick)} {manHyper $w ""}
}


proc resetcolors {{w .}} {
global man curedit

set c [winfo class $w]
set g "gui"; if {$c eq "Text"} {set g "text"} elseif {[string match "*utton" $c]} {set g "butt"}
set foreground [set selector [set insertbackground $man(${g}fg)]]
set background $man(${g}bg)
set ofg $curedit(${g}fg)
set obg $curedit(${g}bg)

foreach i {foreground background insertbackground selectcolor} {
if {![catch {set color [$w cget -$i]}]} {
if {$color eq $ofg} {$w configure -$i $foreground} \
elseif {$color eq $obg} {$w configure -$i $background}
}
}

set activeforeground $man(activefg)
set activebackground $man(activebg)
set highlightbackground $activebackground
foreach i {activeforeground activebackground highlightbackground} {
catch {$w configure -$i [set $i]}
}

foreach c [winfo children $w] {
resetcolors $c
}
}


proc spec2font {{family "times"} {style "normal"} {points "medium"} {size "m"}} {
global man manx

set slant "roman"; set weight "normal"
switch -exact -- $style {
normal {}
bold {set weight "bold"}
italics {set slant "italic"}
bold-italics {set weight "bold"; set slant "italic"}
default {puts stderr "nonexistent style: $style"; exit 1}
}

if {[set pts [lsearch $manx(sizes) $points]]!=-1} {
set p "[lindex [lrange $manx(pts) $pts end] [lsearch {s m l} $size]]"
} else {set p $points}

set font "-family [list $family] -size $p -weight $weight -slant $slant"

return $font
}



proc manHighlightsSetCmd {{incmd add}} {
global manx curwin bmb
set w $curwin; # or, upvar #0 curwin w
set wh $w.high
set txt "Hi"; if {$incmd eq "add"} {set txt "+"} elseif {$incmd eq "remove"} {set txt "-"}
set cmd "add"; if {$incmd eq "remove"} {set cmd "remove"}
$wh configure -text $txt; set bmb($wh) "manHighlights $w $cmd"
}

proc manHighlights {w {cmd update} {auto 0}} {
global high man manx mani stat

set t $w.show
set status ""
set res ""
set rele {([\d.]+)/(\d+)\.(\d+)}

set f $manx(manfull$w)
if {![catch {set sf [file readlink $f]}]} {
if {[string match /* $sf]} {
set f $sf
} else {
set f [file dirname $f]
set strip 1
while {$strip} {
switch -glob $f {
../* {set f [file dirname $f]; set sf [string range $sf 3 end]}
./* {set sf [string range $sf 2 end]}
default {set strip 0}
}
}
append f /$sf
}
}
set normalf [zapZ [bolg $f ~]]

set var high($normalf)

if {$normalf ne "" && ![info exists $var]} {
set movelist {}
set tail [file tail $normalf]
foreach hi [array names high] {
if {$tail eq [file tail $hi]} {lappend movelist $hi}
}
foreach hi $movelist {
if {[lsearch $manx(highdontask) $hi]!=-1} continue
if {[catch {glob $hi$manx(zglob)}]} {
if {[tk_messageBox -title "Moved Highlight?" -message "It appears that the highlighted page formerly at\n   $hi\nhas moved to\n   $normalf\nMove highlights too?" -icon question -type okcancel] eq "ok"} {
set $var $high($hi); unset high($hi)
incr stat(high-carry)
} else {lappend manx(highdontask) $hi}
break
}
}
}


if {[regexp "add|remove" $cmd]} {
if {![llength [$t tag nextrange sel 1.0]]} {
set errmsg "Select a range of "
if {$cmd eq "add"} {append errmsg "characters to highlight"} else {append errmsg "highlighted characters to unhighlight"}

manWinstderr $w $errmsg
return
}
$t tag $cmd highlight sel.first sel.last
if {$cmd eq "add"} {incr stat(page-highlight-add)} else {incr stat(page-highlight-sub)}
set mani(high,form) {}
selection clear $t
set cmd "update"
}


set tags ""
if {$cmd eq "update"} {
set tags [clock seconds]
foreach {first last} [$t tag ranges highlight] {
eval lappend tags [manHighCompose $t $first $last]
}

set mani(high,form) {}
DEBUG {puts "updating highlights to $tags"}
if {[llength $tags]>1} {set $var $tags} else {catch {unset $var}}
set status "updated"

} elseif {[info exists $var]} {
set tags [set $var]

if {[llength [lsecond $tags]]>1} {
set losertxt ""; set dicey 0
set res "new style"

set newtags [lfirst $tags]; # retain creation date
foreach {ftuple ltuple} [lrange $tags 1 end] {
foreach {first firsttxt predelta fhooklen} $ftuple break
foreach {ldelta lasttxt postdelta lhooklen} $ltuple break

if {[regexp $rele $first all basenum relline charoff secttitle]} {
set basesect "js$basenum"
if {[lsearch $manx(sectposns$w) $basesect]!=-1} {
set first [$t index "$basesect linestart+${relline}l+${charoff}c"]
if {$manx(mode$w) eq "texi"} {texiFault $t $basesect}
}
}

set new [manHighlightAttach $t  $first $firsttxt $predelta $fhooklen   $ldelta $lasttxt $postdelta $lhooklen]
foreach {status firstnew ldeltanew} $new break
if {$status eq "LOSE"} {
incr stat(high-lose)
append losertxt "[string range $firsttxt 0 [expr {$predelta-1}]] / [string range $firsttxt $predelta end] ($first)   ...   [string range $lasttxt 0 [expr {[string length $lasttxt]-$postdelta}]] / [string range $lasttxt [expr {[string length $lasttxt]-$postdelta+1}] end] (+$ldelta)\n"
append res ", lost one"
} elseif {$firstnew!=$first || $ldeltanew!=$ldelta} {
incr stat(high-move)
eval lappend newtags [manHighCompose $t $firstnew "$firstnew+${ldeltanew}c"]
if {$status eq "DICEY"} { set dicey 1; append res ", dicey move" }
} else {
incr stat(high-exact)
lappend newtags $ftuple $ltuple
append res ", exact"
}
}

set warningtxt ""

if {$losertxt ne ""} {
manTextPlug $t end "\n\n\nCouldn't attach these highlights:\n" b $losertxt {} "\n"
append warningtxt "Some highlights could not be repositioned.  See the bottom of the page for a list.  They will be forgotten unless they are reapplied manually now.   "
}
if {$dicey} {
append warningtxt "Some highlights have moved considerably and may not have been repositioned correctly.  You may want to verify them now.   "
}
if {$warningtxt ne "" && !$auto} {
tk_messageBox -title "Warning" -message $warningtxt -icon warning -type ok
}

set $var $newtags
set tags $newtags

} else {
set res "old style"
if {![file isfile $f] || [file mtime $f]<=[lfirst [set $var]]} {
append res ", OK"
} else {
if {!$auto && [tk_messageBox -title "Warning" -message "Highlights out of date for $f.  Delete them?" -icon question -type yesno] eq "no"} {
set $var [set tags "[file mtime $f] [lrange [set $var] 1 end]"]
}
append res ", out of date"
}

after 1 manHighlights $w update
}
}


foreach tag {halwaysvis highlight highlight-meta} {$t tag remove $tag 1.0 end}


set m [set mb $w.high].m
$m delete 0 last

foreach {first last} [lrange $tags 1 end] {
if {[llength $first]>1} {
set first [lfirst $first]
if {[regexp $rele $first all basenum relline charoff secttitle]} {set first [$t index "js$basenum linestart+${relline}l+${charoff}c"]}
set last "$first+[lfirst $last]c"
}
$t tag add highlight $first $last

if {$manx(tryoutline$w) && $man(highlight-show) ne "never"} {nb $t $man(highlight-show) $first $last}

if {$auto} { $t yview -pickplace $last; update idletasks; after 1000 }
set label \
[string range [manHighNormalize [$t get $first $last]] 0 $man(high,hcontext)]
$m add command -label $label \
-command "incr stat(page-highlight-go); manOutlineYview $t $first; $t yview scroll \[expr 5-\$man(high,vcontext)] units"
}
manShowTagDist $w highlight 3

if {$manx(tryoutline$w) && $man(highlight-show) ne "halwaysvis"} {
foreach now $manx(sectposns$w) next $manx(nextposns$w) {
if {[$t tag nextrange highlight $now $next-1l]!=""} {
for {set sup "$now.0"} {[regexp $manx(supregexp) $sup all supnum]} {set sup "js$supnum"} {
foreach {ts te} [$t tag nextrange outline "js$supnum linestart"] break; append ts "+1c"
catch {$t tag add highlight-meta $ts $te}
}
}
}
}


if {[llength $tags]>1} {catch {eval $mb configure $man(highlight)}} else {$w.high configure -foreground $man(buttfg) -background $man(buttbg) -font gui}
manHighlightsSetCmd "Hi"
manMenuFit $m

return $res
}




proc manHighCompose {t first last} {
global manx

set excerptmax 30; set hookmax 20

scan [$t index $first] "%d.%d" fline fchar
scan [$t index $last] "%d.%d" lline lchar
set rlen [string length [$t get $first $last]]
set elen [min $excerptmax $rlen]
DEBUG {puts "EXCERPTING first=$first, last=$last, rlen=$rlen, elen=$elen"}

set fsi "$first linestart"
scan [$t index [set fei "$first lineend"]] "%d.%d" junk fendchar
set exhooklen [min $elen [expr {$fendchar-$fchar+1}]]
DEBUG {puts "first\tfstartchar=0, fendchar=$fendchar, exhooklen = $exhooklen"}
if {$exhooklen>=$hookmax} {
set hooklen [string length [manHighNormalize [$t get $first $first+${exhooklen}c]]]
set prelen 0
set excerpttxt [manHighNormalize [$t get $first $first+${elen}c]]
} else {
set prei "$first-[expr {$hookmax-$exhooklen}]c"; if {[$t compare $prei < $fsi]} {set prei $fsi}
set excerpttxt [manHighNormalize [$t get $prei $first+${elen}c]]
set posti "$first+${elen}c"; if {[$t compare $posti > $fei]} {set posti $fei}
set hooklen [string length [manHighNormalize [$t get $prei $posti]]]
set prelen [expr {$hooklen-[string length [manHighNormalize [$t get $first $posti]]]}]
}
DEBUG {puts "|$excerpttxt|, $prelen, $hooklen"}

set firsttag [list [manPosn2OutnOff $t $first] $excerpttxt $prelen $hooklen]

if {!$hooklen} { return "" }


scan [$t index [set esi "$last linestart"]] "%d.%d" junk lstartchar
scan [$t index [set eei "$last lineend"]] "%d.%d" junk lendchar
set exhooklen [min $elen [expr {$lchar-$lstartchar+1}]]
DEBUG {puts "end\tlstartchar=$lstartchar, lendchar=$lendchar, exhooklen = $exhooklen"}
if {$exhooklen>=$hookmax} {
set hooklen [string length [manHighNormalize [$t get $last-${exhooklen}c $last]]]
set postlen 0
set excerpttxt [manHighNormalize [$t get $last-${elen}c $last]]
} else {
set posti "$last+[expr {$hookmax-$exhooklen}]c"; if {[$t compare $posti > $eei]} {set posti $eei}
set excerpttxt [manHighNormalize [$t get $last-${elen}c $posti]]
set prei "$last-${elen}c"; if {[$t compare $prei < $esi]} {set prei $esi}
set hooklen [string length [manHighNormalize [$t get $prei $posti]]]
set postlen [expr {$hooklen-[string length [manHighNormalize [$t get $prei $last]]]}]
}
set lasttag [list $rlen $excerpttxt $postlen $hooklen]
DEBUG {puts "|$excerpttxt|, $hooklen, $postlen"}

return [list $firsttag $lasttag]
}



proc manHighNormalize {raw {maxlen 0}} {
set new [string trim $raw]

regsub "\\|+\n" $new "\n" new
regsub {^\|+\s} $new "\n" new

regsub -all -- "-\n" $new "\n" new
regsub -all {\s+} $new " " new

if {$maxlen} { set new [string range $new 0 $maxlen] }

return $new
}

proc manHighRegexp {normal} {
set regexp [stringregexpesc $normal]
regsub -all {\s+} $regexp {[\s|-]*} regexp
return $regexp
}


proc manHighlightAttach {t first firsttxt predelta fhooklen  ldelta lasttxt postdelta lhooklen   {status "GOOD"}} {
global manx curwin
DEBUG {puts "ATTACH: $first $firsttxt $predelta $fhooklen   $ldelta $lasttxt $postdelta $lhooklen  $status"}

if {!$fhooklen} { set fhooktxt $firsttxt } else {
set len [string length $firsttxt]
set fhooktxt [string range $firsttxt 0 [expr {$fhooklen-1}]]
set fextxt [string range $firsttxt $predelta end]
set fpretxt [string range $firsttxt 0 [expr {$predelta-1}]]
}
if {!$lhooklen} { set lhooktxt $lasttxt } else {
set len [string length $lasttxt]
set lhooktxt [string range $lasttxt [expr {$len-$lhooklen}] end]
set lextxt [string range $lasttxt 0 [expr {$len-$postdelta-1}]]
set lhookextxt [string range $lhooktxt 0 [expr {[string length $lhooktxt]-$postdelta-1}]]
set lposttxt [string range $lasttxt [expr {$len-$postdelta}] end]
}

DEBUG {puts "first = $first, |$fhooktxt|\nlast = +$ldelta, |$lhooktxt|"}



if {[$t compare $first >= end]} { set first [$t index end-1l] }
set flen [string length $fhooktxt]
set fpt ""

set found 0
set fregexp [manHighRegexp $fhooktxt]
set viz [expr {$manx(tryoutline$curwin)?"-elide":"--"}]
set ffw [$t search -forwards -regexp $viz $fregexp $first end]
set fbk [$t search -backwards -regexp $viz $fregexp $first 1.0]
if {$ffw eq "" && $fbk eq ""} {
} elseif {$ffw eq ""} {
set fpt $fbk
set found 1
DEBUG {puts "only found backward from $first at $fbk"}
} elseif {$fbk eq ""} {
set fpt $ffw
set found 1
DEBUG {puts "only found foward from $first at $ffw"}
} else {
scan $first "%d.%d" line char
scan $ffw "%d.%d" fline fchar; set difffw [expr {$fline-$line}]; set dcfw [expr {abs($fchar-$char)}]
scan $fbk "%d.%d" bline bchar; set diffbk [expr {$line-$bline}]; set dcbk [expr {abs($char-$bchar)}]
if {$diffbk<$difffw} {set fpt $fbk} elseif {$difffw<$diffbk} {set fpt $ffw} else {
if {$dcbk<$dcfw} {set fpt $fbk} else {set fpt $ffw}
}
set found 1
DEBUG {puts "found point $first forward ($ffw) and back ($fbk), closer is $fpt"}
}
scan $fpt "%d.%d" fline fchar


if {$found} {
if {$fhooklen} {

set must [$t search -forwards -regexp -count delta $viz [manHighRegexp $fpretxt] $fpt end]
set fpt [$t index "$fpt+${delta}c"]

set txt [$t get $fpt "$fpt+1000c"]
if {![regexp -indices -- [manHighRegexp $fextxt] $txt all]} { set found 0 }

} elseif {$flen>=20} {
if {[expr {abs($line-$fline)>200}]} { set found 0 }
}
}

if {!$found} {
if {$fhooklen} {
return [manHighlightAttach $t $first $fextxt 0 0  $ldelta $lasttxt $postdelta $lhooklen  $status]

} elseif {$flen>10} {
set chop [max 9 [expr {int($flen/2)}]]
return [manHighlightAttach $t $first [string range $fhooktxt 0 $chop] 0 0  $ldelta $lasttxt $postdelta $lhooklen "DICEY"]
} else {
return "LOSE"
}
}



set found 0
set llen [string length $lhooktxt]
set last "$fpt+${ldelta}c-${llen}c"
set lregexp [manHighRegexp $lhooktxt]
set lfw [$t search -forwards -regexp -count lfwcnt $viz $lregexp $last end]
set lbk [$t search -backwards -regexp -count lbkcnt $viz $lregexp $last $fpt]
if {$lfw eq "" && $lbk eq ""} {
} elseif {$lfw eq ""} {
set lpt $lbk
set llen $lbkcnt
set found 1
DEBUG {puts "end only found backward from $fpt at $lbk"}
} elseif {$lbk eq ""} {
set lpt $lfw
set llen $lfwcnt
set found 1
DEBUG {puts "end only found foward from $fpt at $lfw"}
} else {
scan $fpt "%d.%d" line char
scan $lfw "%d.%d" fline fchar; set difffw [expr {$fline-$line}]; set dcfw [expr {abs($fchar-$char)}]
scan $lbk "%d.%d" bline bchar; set diffbk [expr {$line-$bline}]; set dcbk [expr {abs($char-$bchar)}]
if {$diffbk<$difffw} {set lpt $lbk; set llen $lbkcnt} elseif {$difffw<$diffbk} {set lpt $lfw; set llen $lfwcnt} else {
if {$dcbk<$dcfw} {set lpt $lbk; set llen $lbkcnt} else {set lpt $lfw; set llen $lfwcnt}
}
set found 1
DEBUG {puts "found end point $fpt forward ($lfw) and back ($lbk), closer is $lpt"}
}


if {$found} {
if {$lhooklen} {
set rx [manHighRegexp $lhookextxt]
set posti [$t search -count llen -regexp $viz $rx $lpt end]
DEBUG {puts "$t search -count llen -regexp $viz $rx $lpt end"}


set rx [manHighRegexp $lextxt]; append rx "\$"
set txt [$t get "$lpt-1000c" "$lpt+${llen}c"]
if {![regexp -indices -- $rx $txt all]} {set found 0}
}

set nldelta [string length [$t get $fpt "$lpt+${llen}c"]]

if {$llen>=20} {
if {$nldelta>[expr {10*$ldelta}]} {set found 0}
}
}

if {!$found} {
if {$lhooklen} {
return [manHighlightAttach $t $fpt $firsttxt $predelta $fhooklen   $ldelta $lextxt 0 0  $status]

} elseif {$llen>10} {
set chop [max 9 [expr {int($llen/2)}]]
set d [expr {$llen-$chop}]; set lhooktxt [string range $lhooktxt $d end]
return [manHighlightAttach $t $fpt $firsttxt $predelta $fhooklen  $ldelta $lhooktxt 0 0  "DICEY"]

} else {
set nldelta $ldelta
set status DICEY
}
}


return [list $status $fpt $nldelta]
}
set man(versiondiff) 1; set manx(versiondiff-v) {1 0}; set manx(versiondiff-t) {"yes" "no"}
set manx(edrx) {^(\d+),?(\d*)([adc])(\d+),?(\d*)$}

set manx(vdiff) $man(vdiff)

proc manVersionDiff {f w} {
global man manx

if {[string match "*/RCS/*,v" $f]} {
set rcsf $f
set dir [file dirname [file dirname $f]]
set tail [file tail $f]; set tail [string range $tail 0 [expr {[string length $tail]-3}]]
set f $dir/$tail
} elseif {[regexp {(.*)/(([^/]+)\.([^\.]+))} $f all dir tail rootname suffix]} {
set rcsf "$dir/RCS/$tail,v"
} else return
if {![file readable $rcsf]} {return ""}

set fid [open $manx(longtmp) "w"]; puts $fid ".ll $man(columns)\n.hym 20"; close $fid

set cachedir $dir
if {[regsub {/man([^/]+)$} $dir {/cat\1} d2]} {set cachedir $d2}
append cachedir $manx(effcols)
if {![file writable $cachedir] && ![file writable [file dirname $cachedir]]} {
if {[regexp {^(/usr)?/(.*)man/man(.*)$} $dir all junk prefix suffix]} {
set cachedir "$man(fsstnddir)/${prefix}cat$suffix$manx(effcols)"
}
}
append cachedir "/RCSdiff"

set cachefile "$cachedir/$tail"
set existingcachefile [lfirst [glob -nocomplain "$cachefile$manx(zoptglob)"]]
if {[file readable $existingcachefile] && [file mtime $existingcachefile]>[file mtime $f] && [file mtime $existingcachefile]>[file mtime $rcsf] && [file mtime $existingcachefile]>$manx(mtime)} {
if {[regexp $manx(zregexp) $existingcachefile]} {set pipe "|$man(zcat) "} else {set pipe ""}
set fid [open "$pipe$existingcachefile"]; set diffs [read $fid]; close $fid

} else {
cursorBusy
cd $dir
manWinstdout $w "Computing diffs for $tail $manx(effcols) ..." 1

set search 1
set insym 0
set fid [open "|$man(rlog) $tail"]
while {$search && [gets $fid line]!=-1} {
if {!$insym} {
if {[regexp "^\[ \t\]+" $line]} {
if {[regexp "^\[ \t\]+checkpoint: (\[0-9\\.\]+)\$" $line all vnum]} {
set search 0
}
continue

} else {set insym 0}
}
if {[regexp {^revision ([\d\.]+)$} $line all vnum]} {
catch {exec $man(rcsdiff) -r$vnum $tail} info
foreach line [split $info "\n"] {
if {[regexp $manx(edrx) $line]} {
set search 0; break
}
}
}
}
catch {close $fid}



set tmpf /tmp/tkman[pid]
set format "$man(format) | $manx(rman) -f ASCII -N"
catch {eval exec $man(co) -p$vnum $tail | $format > $tmpf} info

catch {set diffs [eval exec [manManPipe $tail] | $format | $manx(vdiff) $tmpf -]} diffs
file delete -force $tmpf
file delete -force $manx(longtmp)

set newdiffs {}

set skip 0; set keep 0
set lines [split $diffs "\n"]
for {set linenum 0} {$linenum<[llength $lines]} {incr linenum} {
set line [lindex $lines $linenum]
if {$keep} {incr keep -1; append newdiffs [string range $line 2 end] "\n"; continue
} elseif {$skip} {incr skip -1; continue}
if {![regexp $manx(edrx) $line all n1 n2 cmd n3 n4]} break
if {$n2 eq ""} {set n2 $n1}; if {$n4 eq ""} {set n4 $n3}
set lcntold [expr {$n2-$n1+1}]; set lcntnew [expr {$n4-$n3+1}]
if {$cmd eq "a"} {
set skip $lcntnew
append newdiffs "0a$lcntnew@$n3\n"
} elseif {$cmd eq "c"} {

set nrx "\[ \t\n|\]+"
set cold ""; set cnew ""
set i 0
for {set i 0} {$i<$lcntold} {incr i} {append cold [string range [lindex $lines [expr {$linenum+1+$i}]] 2 end] "\n"}
for {set i 0} {$i<$lcntnew} {incr i} {append cnew [string range [lindex $lines [expr {$linenum+1+$lcntold+1+$i}]] 2 end] "\n"}
regsub -all $nrx [string trim $cold] " " ncold
regsub -all $nrx [string trim $cnew] " " ncnew

if {$ncold ne $ncnew} {
set keep $lcntold
set skip [expr {1+$lcntnew}]
append newdiffs "${lcntold}c$lcntnew@$n3\n"
} else {
incr linenum [expr {$lcntold+1+$lcntnew}]
}

} else { # d
set keep $lcntold
append newdiffs "${lcntold}c0@$n3\n"
}
}

set diffs $newdiffs

set writedir $cachedir
set mkdirs {}
while {![file exists $writedir]} {
lappend mkdirs $writedir
set writedir [file dirname $writedir]
}
if {[file writable $writedir]} {
foreach mkdir [lreverse $mkdirs] {file mkdir $mkdir}
}


if {[file writable $cachedir]} {
if {[file writable $cachedir]} {
if {$existingcachefile ne ""} {file delete $existingcachefile}
set fid [open $cachefile "w"]; puts $fid $diffs; close $fid
catch {eval file delete [glob $cachefile.$manx(zglob)]}
eval exec $man(compress) $cachefile
} else {manTextPlug $w.show 1.0 "Couldn't cache version differences: $cachedir not writable" b}
}
cursorUnset
}

return $diffs
}


proc manVersionDiffMakeCache {w t} {
global mani manx man

manTextOpen $w
foreach sect $mani(manList) {
foreach dir $mani($sect,dirs) {
$t insert end $dir b "     "
set rcsdir "$dir/RCS"

set cachedir $dir
if {[regsub {/man([^/]+)$} [file dirname $dir] {/cat\1} d2]} {set cachedir $d2}
append cachedir $manx(effcols)
if {![file writable $cachedir] && ![file writable [file dirname $cachedir]]} {
if {[regexp {^(/usr)?/(.*)man/man(.*)$} $dir all junk prefix suffix]} {
set cachedir "$man(fsstnddir)/${prefix}cat$suffix$manx(effcols)"
}
}
append cachedir "/RCSdiff"
set writedir $cachedir
while {![file exists $writedir]} {set writedir [file dirname $writedir]}

set errmsg ""
if {![file exists $rcsdir]} {set errmsg "no versioning information (RCS directory)"
} elseif {![file readable $rcsdir]} {set errmsg "$rcsdir not readable"
} elseif {![file writable $writedir]} {set errmsg "$cachedir not writable/creatable (need perissions on $writedir)"
}

$t insert end "[expr {$errmsg==""?"CACHEING":$errmsg}]\n"
update idletasks; $t see end
if {$errmsg ne ""} continue

foreach rcsfile [lsort -dictionary [glob -nocomplain "$rcsdir/*,v"]] {
foreach cols $manx(columns-v) {
set tmp $manx(effcols); set manx(effcols) [expr {$cols==65?"":"@$cols"}]
manVersionDiff $rcsfile $w
set manx(effcols) $tmp
}
}
}
}
manTextClose $w
}


proc manVersion {w t f} {
global man manx

set diffcnt 0
if {[set diffs [manVersionDiff $f $w]] eq ""} {return $diffcnt}
set cmdrx {(\d+)([acd])(\d+)@(\d+)}

set cmd XXX
set deltal 0; set atl 0
set dell 0
set tags ""
foreach line [split $diffs "\n"] {

if {$cmd eq "c" && $dell==1 && $dell0==1 && $man(columns)==5000} {
set dell 0
set newline [$t get $ts $ts+1l]
set startpre 0; if {[regexp -indices "^(\\|?\[ \t]+)" $newline indices]} {
set startpre [expr {1+[lsecond $indices]}]
set newline [string range $newline $startpre end]
}
$t delete "$ts linestart+${startpre}c" "$ts lineend"
eval $t insert "{$ts linestart+${startpre}c}" [textmanip::wdiff $line $newline]
foreach tag $tagshere {$t tag add $tag "$ts linestart" "$ts lineend"}
continue
}

if {$dell} {
$t insert $ts "|$line\n" $tags; incr deltal
set ts "[expr {$atl+$deltal}].0"
incr dell -1
continue
}

DEBUG {		if {![regexp $cmdrx $line all dell cmd insl atl]} {puts "NO MATCH on\t$line"}}
if {![regexp $cmdrx $line all dell cmd insl atl]} break
set dell0 $dell
incr diffcnt
DEBUG {puts "applying $dell *$cmd* $insl @ $atl"}
set ts "[expr {$atl+$deltal}].0"

if {[regexp "a|c" $cmd]} {
set te "[expr {$atl+$deltal+$insl}].0"
$t tag add diff$cmd $ts $te
for {set ci 0} {$ci<$insl} {incr ci} {
set cbi "[expr {$atl+$deltal+$ci}].0"
if {[$t get $cbi] eq ""} {append cbi "+1c"}; # skip over outline image
if {[$t get $cbi] ne "|"} {$t insert $cbi "|"}
}
}
if {[regexp "c|d" $cmd]} {
set tagshere [$t tag names $ts]
set tags [concat [lmatches areajs* $tagshere] [lmatches elide $tagshere] diffd]
}
}

return $diffcnt
}

proc manVersionClear {} {
global man manx

foreach dir $manx(paths) {
if {[string match "*/catman*" $dir]} continue

catch {eval file delete -force [glob $dir/cat*/RCSdiff/*]}
catch {eval file delete -force [glob $dir/cat*/RCSdiff]}
}
}

proc manGlimpse {name {opts ""} {w .man}} {
global man manx

set dirs $man(glimpsestrays)

set len [llength $name]
if {$len>=2} {
if {[string match "-*" $name]} {
set name [lindex $name end]; set opts [concat $opts [lrange $name 0 [expr {$len-1-1}]]]
} else {
set name [tr $name {\s} ";"]
}
}
if {$man(indexglimpse) eq "distributed"} {
set texindexdir [file join $man(texinfodir) glimpse]
if {$man(texinfodir) ne "" && [file readable $texindexdir]} {lappend dirs $texindexdir}

if {$man(rfcdir) ne "" && [file readable $man(rfcdir)]} {lappend dirs $man(rfcdir)}
foreach dir $man(indexalso) { if {[file readable $dir]} {lappend dirs $dir} }

foreach d $manx(paths) {
if {$man($d)} {	lappend dirs $d }
}
} else {
}

manGlimpse2 $name $dirs $opts $w
}

set manx(glimpse-pattern) ""; # shouldn't need to set it here, but just to be safe
proc manGlimpse2 {name dirs {auxopts ""} {w .man}} {
global man manx mani sbx env stat STOP texi

if {$manx(shift)} {set manx(shift) 0; set w [manInstantiate]}
set t $w.show; set wi $w.info

if {$name eq ""} {set name $manx(man$w)}
if {$name eq ""} {
manWinstderr $w "Type in regular expression for full text search"
return
}
set showname $name

set opts "-y"
if {$man(regexp,case)!=-1 || [string is lower $name]} {append opts "i"}
if {$man(maxglimpse) ne "none"} {append opts " -L $man(maxglimpse):0:5"}

set g1 "$man(glimpse) $auxopts $opts"
regsub -- {-([^ /]*)N} $g1 {-Z\1} g2


set foundList ""
set errorList ""


foreach d $dirs {
if {![file readable [file join $d ".glimpse_index"]]} continue
DEBUG {puts "index search: $g1 -H $d $name"}

if {![catch {set matches [eval exec "$g1 -N -H $d {$name} 2>/dev/null"]} info]} {
set foundList [concat $foundList [lsort [split $matches "\n"]]]
} else {set errorList [concat $errorList [list "error with glimpsing $d:"] [split $info "\n"]]}
}
set fIndexonly [expr {[llength $foundList]>$man(maxglimpseexcerpt)}]



if {!$fIndexonly} {
set foundList ""; # replace existing hit list with one with excerpts
set errorList ""


set STOP 0
cursorBusy

foreach d $dirs {
if {![file readable [file join $d ".glimpse_index"]]} continue
set glz ""; if {[file readable [file join $d ".glimpse_filters"]] && [file size [file join $d ".glimpse_filters"]]>1} {set glz "-z"}
manWinstdout $w "Glimpsing for \"$showname\" in $d ..."; update; # not "update idletasks" because want to accept stop requests from keyboard (should change "man" to "STOP" and reprogram so can stop with a click too)
DEBUG {puts "$g2 -H $d $name"}
if {$STOP} {set STOP 0; break}
if {![catch {set matches [eval exec "$g2 $glz -O -H $d {$name} 2>/dev/null"]} info]} {
set foundList [concat $foundList [split $matches "\n"]]
} else {set errorList [concat $errorList [list "error with glimpsing $d:"] [split $info "\n"]]}
}
}



set foundform ""
set found 0

foreach errmsg $errorList {lappend foundform "$errmsg\n" i}
if {[llength $errorList]} {lappend errmsg "\n\n" {}}

set texindexdir [file join $man(texinfodir) glimpse]
if {$man(texinfodir) eq "" || ![file readable $texindexdir]} {set texindexdir ""}
if {$texindexdir ne ""} {
texiDatabase $man(texinfodir)
set texifound {}
}


foreach page $foundList {
set page [string trimright $page ":"]


if {$texindexdir ne "" && [string match [file join $texindexdir "*"] $page]} {
set mapped ""

set mapto [zapZ [file tail $page]]
foreach canon $texi(texinfo,paths) {
if {[string match /*/$mapto [zapZ $canon]]} {set mapped $canon; break}
}
if {$mapped eq ""} {
set mapto [file rootname [file tail [file dirname $page]]]
foreach canon $texi(texinfo,paths) {
if {[string match /*/$mapto [file dirname $canon]]} {set mapped $canon; break}
}
}
if {$mapped ne "" && [lsearch $texifound $mapped]==-1} {lappend texifound [set page $mapped]} else {set page ""}; # ... else continue
}


if {$page eq ""} {
} elseif {[string match "/*" $page]} {
lappend foundform "[bolg $page ~]\n" manref
incr found
} else {
lappend foundform "     $page\n" sc
}
}
manWinstdout $w ""
cursorUnset


set error [string length $errorList]
if {!$found && !$error} {
manWinstderr $w "$name not found in full text search"
} else {
manNewMode $w glimpse; incr stat(glimpse)
set mani(glimpse,update) [clock seconds]
set form {}
lappend form " Glimpse full text search for \"$name\"\n\n" {}

if {$error} {
lappend form "Errors while Glimpsing:\n\n" {}
}


set mani(glimpse,form) [concat $form $foundform]
set mani(glimpse,cnt) $found
set mani(glimpse,shortvolname) "glimpse"

set manx(search,string$w) [set manx(glimpse-pattern) [tr [tr [llast $name] ";" "|"] "," "|"]]
set sbx(lastkeys-old$t) [llast $name]

.vols entryconfigure "*glimpse*" -state normal
manShowSection $w glimpse

if {!$fIndexonly} "
after 1000 {
searchboxSearch \$manx(search,string$w) 1 \$man(regexp,case) search $t
foreach {s e} \[$t tag ranges search] {$t tag remove search \$s+1c \$e}
}
"
}
}


set mani(glimpseindex,update) 0
proc manGlimpseIndexShow {} {
global man manx mani curwin

set gi [file join $man(glimpsestrays) ".glimpse_index"]
if {$man(indexglimpse) ne "unified" || ![file readable $gi] || $mani(glimpseindex,update)>[file mtime $gi]} return

set fid [open $gi]; set indexglimpse [read $fid]; close $fid
regsub -all "\002\[^\n\]+" $indexglimpse "" indexglimpse; # offset into partitions -- also \002.... notrail -- 
regsub -all "\[\001-\011\013-\037\]+" $indexglimpse "" indexglimpse; # noctrl
while {[regsub -all "\n\[_-\]+\n" $indexglimpse "\n" indexglimpse]} {}; # nobox
while {[regsub -all "\n\[^\n\]\[^\n\]?\[^\n\]?\n" $indexglimpse "\n" indexglimpse]} {}; # misses some?  -- no123
while {[regsub -all "\n\[^_a-z\]\[^\n\]*\n" $indexglimpse "\n" indexglimpse]} {}; # no noise

set index {}; set sub {}; set och2 "__"
foreach i [lsort $indexglimpse] {
set ch2 [string range $i 0 1]
if {$ch2 ne $och2} {lappend index [join $sub "\t"] manref "\n\n" {}; set sub {}; set och2 $ch2}
lappend sub $i
}
if {$sub ne ""} {lappend index [join $sub "\t"] manref}

set mani(glimpseindex,update) [clock seconds]
set mani(glimpseindex,form) $index
set mani(glimpseindex,cnt) [llength $indexglimpse]
}


set mani(glimpsefreq,update) 0
proc manGlimpseFreqShow {} {
global man manx mani curwin

set gi [file join $man(glimpsestrays) ".glimpse_index"]
set gp [file join $man(glimpsestrays) ".glimpse_partitions"]
if {$man(indexglimpse) ne "unified" || ![file readable $gi] || ![file readable $gp] || $mani(glimpseindex,update)>[file mtime $gi]} return

set mani(glimpsefreq,form) 0
set fid [open $gi]
while {![eof $fid]} {
if {![regexp "(\[^\002]+)\002(....)" [gets $fid] all name bo]} continue
binary scan $bo I offset
puts "$name $offset"
}
close $fid
return
regsub -all "\002\[^\n\]+" $indexglimpse "" indexglimpse; # offset into partitions -- also \002.... notrail -- 
regsub -all "\[\001-\011\013-\037\]+" $indexglimpse "" indexglimpse; # noctrl
while {[regsub -all "\n\[_-\]+\n" $indexglimpse "\n" indexglimpse]} {}; # nobox
while {[regsub -all "\n\[^\n\]\[^\n\]?\[^\n\]?\n" $indexglimpse "\n" indexglimpse]} {}; # misses some?  -- no123
while {[regsub -all "\n\[^_a-z\]\[^\n\]*\n" $indexglimpse "\n" indexglimpse]} {}; # no noise

set index {}; set sub {}; set och2 "__"
foreach i [lsort $indexglimpse] {
set ch2 [string range $i 0 1]
if {$ch2 ne $och2} {lappend index [join $sub "\t"] manref "\n\n" {}; set sub {}; set och2 $ch2}
lappend sub $i
}
if {$sub ne ""} {lappend index [join $sub "\t"] manref}

set mani(glimpseindex,update) [clock seconds]
set mani(glimpseindex,form) $index
set mani(glimpseindex,cnt) [llength $indexglimpse]
}


proc manGlimpseIndex {{w .man}} {
global man manx mani stat texi

set var "manx($man(glimpsestrays),latest)"
if {![info exists $var]} {set $var 0}

set texinfodir $man(texinfodir)
if {$texinfodir ne "" && [file writable $texinfodir]} {set texindexdir [file join $texinfodir glimpse]} else {set texinfodir ""}

set rfcdir $man(rfcdir)
if {$rfcdir eq "" || ![file readable $rfcdir]} {set rfcdir ""}

if {$man(indexglimpse) eq "distributed"} {
set dirpairs {}
if {[llength $mani($man(glimpsestrays),dirs)]} {
lappend dirpairs [list $man(glimpsestrays) $mani($man(glimpsestrays),dirs)]
}
foreach dir $manx(paths) {
lappend dirpairs [list $dir $mani($dir,dirs)]
}
if {$texinfodir ne ""} {lappend dirpairs [list $texindexdir $texindexdir]}
if {$rfcdir ne "" && [file writable $rfcdir]} {lappend dirpairs [list $rfcdir $rfcdir]}
foreach dir $man(indexalso) { if {[file writable $dir]} {lappend dirpairs [$dir $dir]} }
} else {
set dirs $mani($man(glimpsestrays),dirs)
foreach dir $manx(paths) {
set dirs [concat $dirs $mani($dir,dirs)]
}
if {$texinfodir ne ""} {lappend dirs $texindexdir}
if {$rfcdir ne ""} {lappend dirs $rfcdir}
foreach dir $man(indexalso) { if {[file readable $dir]} {lappend dirs $dir} }
set dirpairs [list [list $man(glimpsestrays) $dirs]]
}

if {$texinfodir ne ""} {
texiDatabase $man(texinfodir)

catch {file mkdir $texindexdir}
cd $texindexdir
catch { eval file delete [glob *] }; # clean up everybody in case deleted some from dir.tkman...
set texlns {}; set manx($texindexdir,latest) [file mtime [file join $texinfodir "dir.tkman"]]
foreach tex $texi(texinfo,paths) {
set texdir [file dirname $tex]
if {![file readable $texdir]} continue
set texlist [glob [file join $texdir "*.texi*"]]
set cnt [llength $texlist]
foreach texexcept {version gpl} {if {[lsearch -glob $texlist */$texexcept.texi*]!=-1} {incr cnt -1}}
if {$cnt==1} {set makeme $tex; set nameme [file tail $tex]} else {set makeme $texdir; set nameme [file tail $texdir].dir}; # XXX.dir so included in *.*
set ln [file tail $makeme];	# file w/ or w/o .gz (keep .gz so .glimpse_filters works), or directory
if {[lsearch $texlns $ln]==-1} {
exec ln -s $makeme $nameme; lappend texlns $ln
set manx($texindexdir,latest) [max $manx($texindexdir,latest) [file mtime [file join $texinfodir "dir.tkman"]]]
if {$man(indexglimpse) eq "unified"} {set $var [max [set $var] $manx($texindexdir,latest)]}
}
}
}


set buildsec [expr {[lfirst [time {manGlimpseIndex2 $dirpairs $w}]]/1000000}]

if {$buildsec<[expr 60*60]} {set buildfmt "%M:%S"} else {set buildfmt "%T"}
if {$buildsec>30 || $man(time-lastglimpse)==-1} {
set man(time-lastglimpse) [clock format $buildsec -format $buildfmt]
}
incr stat(glimpse-builds)

.occ.db entryconfigure "*Glimpse*" -label "Glimpse Index (last $man(time-lastglimpse))"

}


proc manGlimpseIndex2 {dirpairs {w .man}} {
global man manx mani env

manNewMode $w glimpse
set t $w.show; set wi $w.info

manWinstdout $w "Rebuilding Glimpse database ... "
set mani(glimpse,shortvolname) "Glimpse"
manShowSection $w glimpse
.vols entryconfigure "*glimpse*" -state normal

manTextOpen $w; update idletasks
set cnt [llength $dirpairs]; set cur 1
set foneup 0

foreach pair $dirpairs {
foreach {dir dirs} $pair break
$t insert end "Working on $dir" b " ($cur of $cnt), "
set dircnt [llength $dirs]; set dirtxt [expr {$dircnt==1?"directory":"directories"}]
$t insert end "$dircnt $dirtxt"
$t insert end "\n\n"
$t see end; update idletasks

if {!$dircnt} {
$t insert end "Nothing to index.\n"
incr cur; $t insert end "\n\n"
continue
}

set gzt ".glimpse_filters"
set gf [file join $dir ".glimpse_filenames"]
set gz [file join $dir $gzt]
set gfe [expr {[llength [glob -nocomplain [file join $dir ".glimpse_{filenames,index}"]]]==2}]


set outofdate [expr {!$gfe || [file size $gf]==0 || ([file exists $gz] && [file mtime $gz]>[file mtime $gf]) || [file mtime $gf]<$manx($dir,latest)}]

if {!$outofdate} {
$t insert end "Glimpse index still current.\n" indent

set foneup 1
incr cur; $t insert end "\n\n"
continue
}


if {![file writable $dir]} {
$t insert end "Glimpse index out of date but directory not writable" indent
if {$gfe} {
$t insert end " ... but old Glimpse files found\n" indent
$t insert end "Full text seaching available here using existing files.\n" indent
} else {
$t insert end " ... and Glimpse files not found\n" indent
$t insert end "No full text searching available here.\n" {indent bi}
}

incr cur; $t insert end "\n\n"
continue
}


set gex [file join $dir ".glimpse_exclude"]
if {![file exists $gex]} {
set fid [open $gex "w"]
puts $fid [join {.glimpse_exclude$ ~$ .bak$ /RCS$ /RCSdiff .info .c$ .cc$ .h$ .tex$ .dvi$ .ps$} "\n"]
close $fid
}
set gin [file join $dir ".glimpse_include"]
if {![file exists $gin]} {
set fid [open $gin "w"]
puts $fid "*.*"; # one or more dots in name.  same test for valid page names as elsewhere -- handles .texi too! -- too liberal in accepting dots in directories and .glimpse_filters suffixes, though, as that can count for the dot, but seems to work well enough in practice
close $fid
}


if {![file exists $gz]} {
set fcat [expr {[lsearch -regexp $dirs {/cat[^/]*$}]!=-1}]
set fhp [expr {[lsearch -regexp $dirs {\.Z$}]!=-1}]
set fz 0
foreach d $dirs {
cd $d
if {[lsearch -regexp [glob -nocomplain *] $manx(zregexp)]!=-1} {set fz 1; break}
}

set fid [open $gz "w"]
if {$fhp} {puts $fid "*.Z/*\tzcat <"}
if {$fz} {
set zcat [file tail [lfirst $man(zcat)]]
foreach z $man(zlist) {puts $fid "*.$z\t$man(zcat)"}
}
if {$fcat} {puts $fid "*/cat*/*\trman <"}
close $fid
}


if {[catch {set fid [open "|$man(glimpseindex) -z -H $dir $dirs"]} info]} {
DEBUG {puts "error on: $man(glimpseindex) -z -H $dir $dirs]: $info"}
$t insert end "$info\n" bi
catch {close $fid}; # fid not set?
} else {
DEBUG {puts "$man(glimpseindex) -z -H $dir $dirs"}
fconfigure $fid -buffering line; # doesn't seem to make any difference on a pipe(?)
set blankok 0
while {![eof $fid]} {
gets $fid line
if {![regexp {(^This is)} $line] && ($line ne "" || $blankok)} {
$t insert end "$line\n" tt; $t see end; update idletasks
set blankok 1
}
update idletasks
}
if {[catch {close $fid} info]} { $t insert end "ERRORS\n" {indent bi} $info indent2 "\n" }

if {[file size $gf]==0} {
$t insert end "No files could be indexed.  No full text searching available here.\n" {indent bi}
if {[file exists $gz]} {
$t insert end "Try checking your $gzt file in $dir.  If $gzt wasn't created by TkMan, try deleting it and letting TkMan create one of its own.\n" indent
}
} else {
catch {
file stat $dir dirstat
set perm [format "0%o" [expr {$dirstat(mode)&0666}]]
foreach setperm [glob [file join $dir ".glimpse_*"]] {file attributes $setperm -permissions $perm}
}
}
}

incr cur
$t insert end "\n\n"
}

if {$foneup} {
$t insert end "\nTo force re-indexing of directories that TkMan claims are current, remove all Glimpse index files in that directory, as with `rm <dir> .glimpse_*'.\n" i
}

$t see end
manTextClose $w

set mani(glimpse,form) [list [$t get 1.0 end]]

manWinstdout $w ""
}

proc manGlimpseClear {} {
global man manx
foreach dir [concat $manx(paths) $man(fsstnddir)] {
catch {eval file delete -force [glob [file join $dir ".glimpse_*"]]}
}
}

proc manStatistics {w} {
global man manx mani high default stat env

if {$manx(shift)} {set manx(shift) 0; set w [manInstantiate]}
set t $w.show; set wi $w.info; set m $w.sections.m

manNewMode $w info; incr stat(info)
set manx(hv$w) info
set head "Statistics and Information"
manWinstdout $w $head

manTextOpen $w

$m add command -label "Statistics" -command "incr stat(page-section); $t yview 1.0"
$t insert end "Statistics  " h1
manStatsSet

$t insert end "since startup at [textmanip::recently $manx(startuptime)]"
$t insert end "   \[total since [textmanip::recently $stat(cum-time)]\]\n" i
$t insert end "   'Man is the measure of all things.\n\n" i

$t insert end "TkMan version $manx(version)"
if {$stat(cum-man)} {
set nth [expr {$stat(cum-executions)%100}]
if {$nth>=11 && $nth<=13} {set nth 0} else {set nth [expr {$nth%10}]}
if {$nth>3} {set nth 0}; set th [lindex {th st nd rd} $nth]
$t insert end "\n\t$stat(cum-executions)$th execution"

set days [expr {(0.0+[clock seconds]-$stat(cum-time))/(60*60*24)}]
set timesperday [expr {$stat(cum-executions)/$days}]
if {$timesperday>0.0} {set txt [format "%.2f times per day/%.2f times per weekday" $timesperday [expr {$timesperday*7.0/5.0}]]} else {set txt [format "%.2f days per execution" [expr {1.0/$timesperday}]]}
$t insert end " ($txt)"

$t insert end ", browsing [format %.2f [expr {(0.0+$stat(cum-man))/$stat(cum-executions)}]] pages/execution\n"

if {$manx(mondostats)} {
set days {Mon Tue Wed Thu Fri Sat Sun}
foreach day $days {set mondo($day) [list 0 0 0 0 0]}
foreach point $man(chronobrowse) {
foreach {time counts} [split $point ":"] break
foreach {start duration reading} [split $time "/"] break
if {$duration eq ""} {set duration 0}
if {$reading eq ""} {set reading 0}
foreach {mancnt texcnt rfccnt} [split $counts "/"] break

set day [clock format $start -format "%a"]
scan $mondo($day) "%d %d %d %d %d" instsub secsub mansub texsub rfcsub
incr instsub; incr secsub $duration; 
incr mansub $mancnt; incr texsub $texcnt; incr rfcsub $rfccnt
set mondo($day) [list $instsub $secsub $mansub $texsub $rfcsub]

set year [clock format $start -format "%Y"]
if {![info exists mondoy($year)]} {set mondoy($year) [list 0 0 0 0 0]}
scan $mondoy($year) "%d %d %d %d %d" instsub secsub mansub texsub rfcsub
incr instsub; incr secsub $duration; 
incr mansub $mancnt; incr texsub $texcnt; incr rfcsub $rfccnt
set mondoy($year) [list $instsub $secsub $mansub $texsub $rfcsub]
}
set txt "\n\t"
foreach year [lsort -integer [array names mondoy]] {
scan $mondoy($year) "%d %d %d %d %d" insttot sectot mantot textot rfctot
if {$mantot+$textot+$rfctot!=0} {append txt "$year  $insttot: $mantot/$textot/$rfctot    "}
}
$t insert end $txt sc "     (year/day executions: man/Texinfo/RFC)" i "\n"

set txt "\t"
foreach day $days {
scan $mondo($day) "%d %d %d %d %d" insttot sectot mantot textot rfctot
if {$mantot+$textot+$rfctot!=0} {append txt "[string range $day 0 0] $insttot:$mantot/$textot/$rfctot    "}
}
$t insert end $txt\n sc
}
}
$t insert end "\n"

foreach i $manx(modes) desc $manx(mode-desc) {
$t insert end "$stat($i)\t$desc " "" "\[$stat(cum-$i)\]\n" i
if {$i eq "man"} {
$t delete end-1c
$t insert end ", $stat(man-no) not found " "" "\[$stat(cum-man-no)\]\n" i
$t insert end "\t"
set first 1
foreach j $manx(stats) desc $manx(stats-desc) {
if {[string match "man-*" $j]} {
if {!$first} {$t insert end ",  "}
$t insert end "$stat($j)  $desc " "" "\[$stat(cum-$j)\]" i
set first 0
}
}
$t insert end "\n"
}
}

set pageops 0; set cpageops 0
foreach i [array names stat page-*] {
incr pageops $stat($i)
incr cpageops $stat(cum-$i)
}
$t insert end "$pageops\tpage navigation operations " "" "\[$cpageops\]\n" i
$t insert end "\t"
set first 1
foreach j $manx(stats) desc $manx(stats-desc) {
if {[string match "page-*" $j]} {
if {!$first} {$t insert end ",  "}
$t insert end "$stat($j)  $desc " "" "\[$stat(cum-$j)\]" i
set first 0
}
}
$t insert end "\n"

$t insert end "\tHighlights:  $stat(high-exact) reattached " "" "\[$stat(cum-high-exact)\]" i
$t insert end ",  $stat(high-move) automatically repositioned on changed page  " "" "\[$stat(cum-high-move)\]" i
$t insert end ",  $stat(high-carry) automatically carried to moved page  " "" "\[$stat(cum-high-carry)\]" i
$t insert end ",  $stat(high-lose) unattachable  " "" "\[$stat(cum-high-lose)\]\n" i

$t insert end "$stat(print)\tpages printed  " "" "\[$stat(cum-print)\]\n" i

if {$man(glimpse) ne ""} {$t insert end "$stat(glimpse-builds)\tGlimpse index builds  " "" "\[$stat(cum-glimpse-builds)\]\n" i}


global tk_patchLevel
$t insert end "\nRunning under Tcl [info patchlevel]/Tk $tk_patchLevel\n"
$t insert end "[info cmdcount] Tcl commands executed\n"
catch { $t insert end "Hardware: [exec uname -a]\n" }

$t tag add info 1.0 end; update idletasks


if {[file readable $manx(startup)]} {
$m add command -label "Variables" -command "incr stat(page-section); $t yview [$t index end]"
$t insert end "\nVariables overridden in [bolg $manx(startup) ~]\n\n" h1
set allold 1
foreach i [lsort [array names default]] {
set new [tr $man($i) \n " "]; if {$new eq ""} {set new "(null)"}
set old [tr $default($i) \n " "]; if {$old eq ""} {set old "(null)"}
if {$new ne $old} {
$t insert end "man(" {} $i b ") = " {} $new tt ", " {} "formerly " i $old tt "\n"
set allold 0
}
}
if {$allold} { $t insert end "None\n" }
}


$m add command -label "Full Paths" -command "incr stat(page-section); $t yview [$t index end]"
$t insert end "\nFull paths of supporting executables\n\n" h1
set allfull 1
foreach i $manx(binvars) {
set val [set $i]
$t insert end "$i = $val.   "
foreach j [split $val "|"] {
set bin [lfirst $j]
if {![string match "/*" $bin]} {
$t insert end "  $bin" b " => " "" $stat(bin-$bin) tt
set allfull 0
}
if {[info exists stat(bin-$bin-vers)]} { $t insert end "  (v$stat(bin-$bin-vers))" }
}
$t insert end "\n"
}
if {!$allfull} {
$t insert end "\n" "" "PATH" tt "  environment variable is " "" $env(PATH) tt "\n"
}


$m add command -label "Dates" -command "incr stat(page-section); $t yview [$t index end]"
$t insert end "\nDates\n\n" h1
if {[file readable $manx(startup)]} {
$t insert end "Startup " b "file last save\n\t" {} $manx(startup) tt "\t" {} [textmanip::recently [file mtime $manx(startup)]] i "\n"
}
if {$man(glimpse) ne ""} {
if {$man(indexglimpse) eq "distributed"} {
$t insert end "Distributed Glimpse " {} "indexes" b " latest updates\n"
set paths $manx(paths)
} else { 
$t insert end "Unified Glimpse " {} "index" b " latest update\n"
set paths $man(glimpsestrays)
}

foreach i $paths {
set db $i/.glimpse_index
$t insert end "\t" {} $i tt "\t"
if {[file exists $db]} {
$t insert end [textmanip::recently [file mtime $db]] i "\n"
} else { $t insert end "no index" b "\n" }
}
}


$m add command -label "Volume Mappings" -command "incr stat(page-section); $t yview [$t index end]"
$t insert end "\nVolume-to-directory mappings\n\n" h1

set manpath0 [join $manx(paths) ":"]
$t insert end "MANPATH" sc ": " "" $manpath0 tt "\n"
if {$manx(MANPATH0) ne $manpath0} {
$t insert end "As cleaned up from original " "" "MANPATH" sc ": "
foreach path [split $manx(MANPATH0) ":"] {
$t insert end $path [expr {[lsearch -exact $manx(paths) $path]==-1?"i":"tt"}] ":" tt
}
$t delete end-2c; $t insert end "\n"
}
$t insert end "\n"

foreach i $mani(manList) {
if {![llength $mani($i,dirs)]} continue
$t insert end "Volume $i, [lindex $mani(manTitleList) [lsearch $mani(manList) $i]]\n" b
foreach j $mani($i,dirs) { 
$t insert end "\t" {} [bolg $j ~] tt "\t" {} [textmanip::recently $mani($j,update)] i "\n"
}
}


$m add command -label "Change Log" -command "incr stat(page-section); $t yview [$t index end]"
$t insert end "\nLog of Some Less-trivial Changes\n" h1
$t insert end $manx(changes)

$t tag add info 1.0 end
manTextClose $w

scan [$t index end] %d eot
manLineCnt $w $eot

manYview $w
}



proc manBug {w} {
global man manx mani high default stat env argv0

if {$manx(shift)} { set manx(shift) 0; set w [manInstantiate] }
set t $w.show; set wi $w.info

manNewMode $w bug; incr stat(bug)
set manx(hv$w) bug
set head "Submit Bug Report"
manWinstdout $w $head
manLineCnt $w ""

manTextOpen $w

$t insert end "Select all the text below and paste into your e-mail program.\n"
$t insert end "Before submitting a bug report, first check the home ftp site (ftp://ftp.cs.berkeley.edu/ucb/people/phelps/tcltk) to make sure it hasn't already been fixed in a later version." i "\n\n"


$t insert end "To: phelps@ACM.org\n"
$t insert end "Subject: TkMan bug report\n\n"

$t insert end "Describe the problem:\n\n\n\n" h1


$t insert end "System description information\n\n" h1

$t insert end "X Windows version: _____\n"
$t insert end "window manager: ______\n"

global tk_patchLevel
$t insert end "TkMan version $manx(version)\n"
$t insert end "MANPATH = $manx(MANPATH0)\n"
$t insert end "Tcl [info patchlevel]/Tk $tk_patchLevel\n"
catch { $t insert end "Hardware: [exec uname -a]\n" }

if {[file readable $manx(startup)]} {
$t insert end "\n\nVariables overridden in [bolg $manx(startup) ~]\n\n" h1
set allold 1
foreach i [lsort [array names default]] {
set new [tr $man($i) \n " "]; if {$new eq ""} {set new "(null)"}
set old [tr $default($i) \n " "]; if {$old eq ""} {set old "(null)"}
if {$new ne $old} {
$t insert end "man(" {} $i b ") = " {} $new code ", " {} "formerly " i $old code "\n"
set allold 0
}
}
if {$allold} { $t insert end "None\n" }
$t insert end "\n\n\n"
}

if 0 {
if {[file readable $argv0]} {
$t insert end "First few lines of `tkman' executable\n\n" h1
set fid [open $argv0]
for {set i 0} {$i<6} {incr i} {$t insert end [gets $fid] {} "\n"}
catch {close $fid}
}

}

manTextClose $w
manYview $w
}

set manx(outlinesearch) ""
set manx(subsearch) ""

proc manShowMan {fname {goodnum ""} {w .man}} {
global man manx mani env stat
DEBUG {puts stdout "manShowMan: $fname $goodnum $w"}

if {$manx(shift)} {set manx(shift) 0; set w [manInstantiate]}

set wi $w.info; set t $w.show

if {[string trim $fname] eq ""} return


if {[llength [set filelist [glob -nocomplain -- $fname]]]>1} {
manNewMode $w picklist
manTextOpen $w
$w.show insert end [join $filelist "\n"] manref
manTextClose $w
return
} elseif {[string match /* $fname]} {manShowManFound $fname 0 $w; return}

if {[regexp {^(\.\./|\./|[a-zA-Z]:|[~/$])} $fname]} {
return [manShowManFound [fileexp [lfirst $fname]] 0 $w]
}

regexp {^([^/]+)\?([^/]+)$} $fname all fname manx(subsearch)
regexp {^([^/]+)/([^/]+)$} $fname all fname manx(outlinesearch)



regsub "\\\\" $fname "\a" fname

if {[lsearch $manx(specialvols) $goodnum]!=-1} {set goodnum ""}

set oname [string trimright [string trim [lfirst $fname] { ,?!;"'-}] .]
if {$goodnum ne ""} {set tmp "($goodnum)"} else {set tmp ""}
manWinstdout $w "Searching for \"$oname$tmp\" ..." 1
set fname [string tolower $oname]; # lc w/  () for regexp
set sname [string trim $fname ()]; # lc w/o ()
set oname [string trim $oname ()]; # original case w/o ()

set name $sname; set num ""; set ext ""

if {[regexp {([\w.+-:]+)\s*\(([^)]?)(.*)\)} $fname \
all pname pnum pext]} {
set name $pname; set num $pnum; set ext $pext
DEBUG {puts "(num) = $num"}

} elseif {[regexp {(.+)\.(.)([^.]*)$} $oname all namex sectx extx]
&& [lsearch -exact $manx(manList) $sectx]!=-1
&& [lsearch -exact $manx(mandot) $oname]==-1} {
set name $namex; set num $sectx; set ext $extx
DEBUG {puts ".num = $num"}

} elseif {$goodnum ne ""} {
set num $goodnum
}

if {[lsearch -exact $manx(manList) "$num$ext"]!=-1} {
set num "$num$ext"; set ext ""
}


set ext [string tolower $ext]
if {$man(shortnames)} {set name [string range $name 0 10].*}
if {[catch {regexp $name validregexpcheck}]} {set name [stringregexpesc $name]}
foreach v {fname sname oname name} {regsub "\a" [set $v] "\\" $v}

if {$name eq "tkman"} {manHelp $w; return}

cursorBusy
DEBUG {puts stdout "$name : $num : $ext"}
set manx(searchtime) [lfirst [time {
set foundList [manShowManSearch $name $num $ext]
}]]
cursorUnset
DEBUG {puts stdout "search time: $manx(searchtime)"}

set found [llength $foundList]
if {!$found} {
DEBUG {puts stdout "$name not found: $ext, $num, [file rootname $name], [stringregexpesc $name]"}
if {$ext ne ""} {
manShowMan $name $num $w; return
} elseif {$num ne "" || [file rootname $name] ne $name} {
manShowMan [file rootname $name] {} $w
return
} elseif {$name ne [stringregexpesc $name] && ![string match {*\\*} $name]} {
manShowMan [stringregexpesc $name] {} $w
return
}
}

if {!$found} {
set fuzzyname ""
for {set i 0; set imax [expr {[string length $name]-1}]; set odd 0} {$i<$imax} {incr i; set odd [expr {1-$odd}]} {
append fuzzyname {[} [string range $name $i [expr {$i+1}]]
append fuzzyname {]}
if {$odd} {append fuzzyname "?"} elseif {$i>0} {append fuzzyname ".?"}
}
append fuzzyname {[} [string index $name end] {.]?}

if {[llength [set hiddenList [manShowManSearch $name "" "" 1]]]} {
manNewMode $w picklist
manTextOpen $w
$t insert end "However, found in [textmanip::plural [llength $hiddenList] {disabled path}]:\n\n"
foreach path $hiddenList {$t insert end "[file dirname [file dirname $path]]" b "/[file tail [file dirname $path]]/[file tail $path]\n"}
$t insert end "\nPaths can be enabled with the Paths menu, under the man menu."
manTextClose $w
after 500 $w.man configure -foreground $man(buttbg) -background $man(buttfg)
after 2500 $w.man configure -foreground $man(buttfg) -background $man(buttbg)

} elseif {[llength [set masterList [manShowManSearch $name MASTER]]]} {
manNewMode $w picklist
manTextOpen $w
$t insert end "However, it was found in the master list of manual page directory hierarchies.  You use the [textmanip::plural [llength $masterList] hyperlink] now, but to find this page and others clustered with it in the usual search, add the corresponding directory (named ..." "" "/man" tt ", not ..." "" "/man" tt "n" i ") to your " "" "MANPATH" sc " in a shell.\n\n"
$t insert end "For instance, if the page hyperlink shows " "" "/opt/SUNWrtvc/man/man1/mpeg_rc.1" tt " and your " "" "MANPATH" sc " is " "" "/usr/man:/usr/local/man" tt ", add " "" "/opt/SUNWrtvc/man" tt " to make it " "" "/usr/man:/usr/local/man:/opt/SUNWrtvc/man" tt ".  Then restart TkMan by typing " ""  "retkman" tt ".\n\n"
foreach path $masterList {$t insert end "$path\n" manref}
manTextClose $w

} elseif {$man(tryfuzzy) && [llength [set fuzzyList [manShowManSearch $fuzzyname]]]} {
set minlen [max 4 [expr {[string length $name]-1}]]
set priorityList {}; foreach page $fuzzyList {set fuzlen [string length [file rootname [file tail $page]]]; if {$fuzlen>=$minlen} {lappend priorityList [list $page $fuzlen]}}
if {[llength $priorityList]} {
set foundList {}; foreach pagepri [lsort -decreasing -integer -index 1 $priorityList] {lappend foundList [lfirst $pagepri]}
return [manShowManFound $foundList 0 $w]
}
}

manWinstderr $w "$sname not found"; incr stat(man-no)

} else {
set orname [file rootname $oname]
set priorityList {}; foreach page $foundList {lappend priorityList [list $page [manShowManPriority $page $num $ext $orname $manx(cursect$w)]]}
set foundList {}; foreach pagepri [lsort -decreasing -integer -index 1 $priorityList] {lappend foundList [lfirst $pagepri]}
return [manShowManFound $foundList 0 $w]
}
}


proc manShowManPriority {m num ext orname onum} {
global man manx mani

set d [file dirname $m]; set t [file tail $m]
set r [file rootname $t]; set x [file extension $t]
set n [string index $x 1]; set e [string range $x 2 end]
set gr $r; if {[string index $r 0] eq "g"} {set gr [string range $r 1 end]}

set pri 0
if {$gr eq $orname} {incr pri 128} elseif {[string equal -nocase $gr $orname]} {incr pri 32}
if {$n ne "" && $n==$num} {incr pri 64} elseif {$n==$onum} {incr pri 1}
if {$e ne "" && $e eq $ext} {incr pri 32}
if {$man(preferTexinfo) ^ ![string match "*.texi*" $x]} {incr pri 16}
if {[string equal $man(preferGNU) ""] ^ ([string index $r 0] eq "g" || [regexp -nocase {/gnu} $d])} {incr pri 8}
if {[string match "*/man/man*" $d]} {incr pri 4}
DEBUG {puts "$m => $pri .. $n==$num/$n==$onum/$r==$orname/$e==$ext/*.texi*==$e"}
set pri [expr {$pri<<8}]; # move out of tie breaker space

set p -1; set l [llength $manx(paths)]
while {$d ne "/" && [set p [lsearch -glob $manx(paths) $d*]]==-1} {
set d [file dirname $d]
}

if {$p==-1} {set p $l}
incr pri [expr {$l-$p}]
set pri [expr {$pri<<7}]

set l [llength $mani(manList)]
set p [lsearch -exact $mani(manList) $n]; if {$p==-1} {set p $l}
incr pri [expr {$l-$p}]


return $pri
}


proc manSearchArray {{sectpat ""} {inactive 0}} {
global man manx mani

if {[string match "*MASTER*" $sectpat]} {
set sects "MASTER"
} else {
if {[string match $sectpat ""] || [lsearch $manx(manList) $sectpat]==-1} {set sectpat "*"}
set sects $manx(manList)
}

set vars {}
foreach s $sects {
if {![string match $sectpat $s] || ![info exists mani($s,dirs)]} continue
foreach d $mani($s,dirs) {
set sup [file dirname $d]
if {([info exists man($sup)] && !$man($sup)) ^ $inactive} continue
lappend vars "$s,$d"
}
}
return $vars
}


proc manManComplete {w} {
global manx

set t $w.show; set wi $w.info

set typelen [string length $manx(typein$w)]
if {$typelen<=1} return

set candidates {}
foreach c [string tolower [manShowManSearch "$manx(typein$w).*"]] {
lappend candidates [file tail $c]
}
set cnt [llength $candidates]
if {!$cnt} {
manWinstderr $w "no matches"
return
} elseif {$cnt>=2} {
if {[string length $candidates]<50} {
manWinstderr $w $candidates
} else {
manTextOpen $w
$t insert end $candidates
manTextClose $w
}
}

set typeend [expr {$typelen-1}]
set pfx [lfirst $candidates]; set end [expr {[string length $pfx]-1}]
foreach c $candidates {
set cend [expr {[string length $c]-1}]
if {$end>$cend} {set end $cend; set pfx [string range $pfx 0 $end]}
while {[string range $c 0 $end] ne $pfx} {incr end -1; set pfx [string range $pfx 0 $end]}
if {$end==$typeend} break
}

set manx(typein$w) $pfx
$w.mantypein icursor end
}


proc manShowManSearch {name {sect ""} {ext ""} {inactive 0}} {
global man manx mani manc texi

set foundList {}
set e "(?i)\\m(g|n)?$name\\M"; # include GNU and "new" too, whether preferred or not
set closee "(?i)^(g|n)?$name\$"; # with \m can match after "::" (which C++ and Perl use)

texiDatabase $man(texinfodir)
if {[info exists texi(texinfo,names)]} {
set inx [lsearch -regexp $texi(texinfo,names) $e]
if {$inx==-1} {set inx [lsearch -regexp $texi(texinfo,desc) $e]}
if {$inx>=0} {lappend foundList [lindex $texi(texinfo,paths) $inx]}
}

foreach subvar [manSearchArray "$sect$ext*" $inactive] {
set d [lsecond [split $subvar ","]]
set var manc($subvar)

if {[info exists manc($subvar)] && [set match [lsearch -regexp $manc($subvar) $e]]!=-1} {
foreach p [lrange $manc($subvar) $match end] {
if {[regexp $closee $p]} {

set f "$d/$p"

if {![llength [set actual [glob -nocomplain "$f.?*"]]]} {
if {[regsub {/man([^/]+)$} [file dirname $f] {/cat\1} d2]} {
set actual [glob -nocomplain [file join $d2 "[file tail $f].?*"]]
}
}
foreach i $actual {
zapZ! i
if {[regexp "$manx(bkupregexp)\$" $i]} continue
if {[lsearch $foundList $i]==-1} {lappend foundList $i}
}
}
}
}
}
return $foundList
}




proc manShowManFound {f {keep 0} {w .man}} {
global man manx stat pagecnt stoplist

set t $w.show; set wi $w.info

if {$man(maxpage)} {pack forget $w.kind $w.search}

if {[set trylong [string match "*$manx(longtmp)*" $man(format)]]} {
set fid [open $manx(longtmp) "w"]
puts $fid ".ll $man(columns)\n.hym 20"
close $fid
}

set flen [llength $f]
if {$flen>1} {
set manx(manhits) $f

pack $w.dups -after $w.mantypein -side left -anchor e -padx 10; $w.dups configure -state active
after 2000 raise $w.dups
set m $w.dups.m
$m delete 0 last
foreach i [lrange $f 0 100] {$m add command -label $i -command "incr stat(man-dups); manShowManFound $i 1 \$manx(out$w)"}
manMenuFit $m

set f [lfirst $f]
set keep 1
} elseif {!$keep} {pack forget $w.dups; set manx(manhits) {}}

set f [zapZ [string trim $f]]


if {[string match "*/rfc*.txt" $f]} {
incr stat(rfc); incr stat(txt) -1
manShowRfc $f $w $keep; return
} elseif {[regexp {^[|<]} $f] || [string match "*.txt" $f]} {manShowText $f $w $keep; return
} elseif {[regexp ".*\.texi(nfo)?$manx(zregexpopt)\$" $f]} {manShowTexi $f $w $keep; return
}


manNewMode $w man; incr stat(man)



set frcs "[file dirname $f]/[zapZ [file tail $f]]"
set isrcs 0
if {[regexp {([^/]+):([\d\.]+)$} $f all rcstail rcsrev] 
&& [file readable [set frcs "[file dirname $frcs]/$rcstail"]]} {

set isrcs 1
set fid [open "|$man(co) -p$rcsrev"]

} elseif {[set fg [lfirst [glob -nocomplain $f$manx(zoptglob)]]] ne ""} {
set f $fg

if {[file isdirectory $f]} {
manWinstderr $w "$f is a directory"
return
} elseif {![file readable $f]} {
manWinstderr $w "$f not readable"
return
}


if {![string match "*/man/*" $f] && ![string match "*/catman/*" $f]} {
set fid [open "|[manManPipe $f]"]; set hunk [read $fid 1024]; catch {close $fid}
if {![regexp "(^|\n)(\\.|'\\\")" $hunk]} {
manShowText $f $w $keep
return				
}
}

set fid [open "|[manManPipe $f]"]

} else {manWinstderr $w "$f doesn't exist"; return}

set f0 $f

set tmpdir [file dirname $f]

set so 0
set line1 [set line2 [set line3 ""]]
while {([string trim $line1] eq "" || [regexp {^[.']\\"} $line1]) && ![eof $fid]} {gets $fid line1}
while {[string trim $line2] eq "" && ![eof $fid]} {gets $fid line2}
while {[string trim $line3] eq "" && ![eof $fid]} {gets $fid line3}
catch {close $fid}
if {[regexp {^\.so (man.+/.+)} $line1 all newman]} {
DEBUG {puts stderr "*** single-line .so => $manx(manfull$w): $line1"}
if {[catch {set f [lfirst [glob [file join [file dirname $tmpdir] "$newman*$manx(zoptglob)"]]]}]} return
set tmpdir [file dirname $f]
set so 1
DEBUG {puts stderr "*** new f => $f"}
} elseif {[regexp "SHADOW_PAGE" $line2]} {
regexp {SYSTEM "(?:./)?(.*)">} $line3 all f
set so 1
}

set manx(manfull$w) $f
set manx(man$w) [zapZ [file tail $f]]
if {$isrcs} {set manx(name$w) $f} else {set manx(name$w) [string trimright [file rootname $manx(man$w)] "\\"].[manSetSect $w $f]}

set fdir [zapZ [file dirname $manx(manfull$w)]]
set topdir [file dirname $fdir]
regexp $manx(zdirsect) [file tail $fdir] all manx(num$w)
if {[lsearch $man(manList) $manx(num$w)]==-1} {set manx(num$w) [string index $manx(num$w) 0]}
set cat "$topdir/cat$manx(num$w)$manx(effcols)"


set fsstnd ""
if {[regexp {^(/usr)?/(.*)man/(?:s?)man(.*)$} [file dirname $manx(manfull$w)] all junk prefix suffix]} {
set fsstnd "$man(fsstnddir)/${prefix}cat$suffix$manx(effcols)/$manx(man$w)$manx(zoptglob)"
DEBUG {puts "*** fsstnd = $fsstnd"}
} else {set fsstnd "$man(fsstnddir)/cat@$manx(effcols)/[file dirname $manx(manfull$w)]"}


set gotcat 0
if {$isrcs || [string match "*ignore*" $man(nroffsave)]} {
} elseif {[regexp $man(catsig) $fdir]} {
set manx(catfull$w) $manx(manfull$w)

if {$line2 eq "  Purpose"} {
manShowText $f $w 1
set manx(typein$w) [set manx(name$w) [file rootname [set manx(man$w) [file tail $f]]]]
return
}
set gotcat 1
} else {
DEBUG {puts "regexp on $topdir"}
set bsdi "$cat/[file rootname $manx(man$w)].0$manx(zoptglob)"
set irix "$cat/[file rootname $manx(man$w)].z"
set manx(catfull$w) "$cat{,.Z}/$manx(man$w)$manx(zoptglob)"
DEBUG {puts "manx(man\$w) = $manx(man$w), catfull = $manx(catfull$w)"}


if {[catch {set manfullmtime [file mtime $manx(manfull$w)]}]} {set manfullmtime 0}

foreach catme [list $manx(catfull$w) $fsstnd $bsdi $irix] {
if {$catme eq ""} continue
if {[set path [lfirst [lsort [glob -nocomplain $catme]]]] ne ""
&& [file readable $path] && ([file mtime $path]>=$manfullmtime || !$manx(canformat))} {
set manx(catfull$w) $path
set gotcat 1
break
}
}
}


if {$isrcs} {
set pipe "$man(co) -p$rcsrev $frcs | $man(format)"
} elseif {$gotcat} {
set pipe [manManPipe $manx(catfull$w)]
} elseif {[file exists $manx(manfull$w)]} {
if {[string match */man?* $tmpdir]} {
set topdir [file dirname $tmpdir]
} else {set topdir $tmpdir}
if {[catch {cd $topdir}]} {
manWinstderr $w "Can't cd into $topdir.  This is bad.  Change permissions."
return
}
if {[string match "*compress" $man(nroffsave)] && [file writable "$cat.Z"]} {
append cat ".Z"
}
if {[string match "*/man/sman*/*" $f]} {set format0 "/usr/lib/sgml/sgml2roff $manx(manfull$w)"} else {set format0 "[manManPipe $manx(manfull$w)]"}; append format0 " | $man(format)"

if {[string match "on*" $man(nroffsave)]
} {
set saveerr ""

if {($man(fsstnd-always) || ([file exists $cat]? ![file writable $cat] : ![file writable [file dirname $cat]]))
&& [file writable $man(fsstnddir)] && $fsstnd ne ""} {
set cat [file dirname $fsstnd]
}

set idir ""
DEBUG {puts "cat = $cat"}
foreach dir [file split [string range $cat 1 end]] {
DEBUG {puts "idir = $idir, dir = $dir"}
if {![file exists [file join $idir $dir]]} {
DEBUG {puts "\tmaking $idir/$dir"}
if {[catch "file mkdir $idir/$dir" info]} {
DEBUG {puts "\t  ERROR: $info"}
set saveerr $info
break
} else {
catch {
if {"$idir/$dir" ne $cat || ![string match cat* $dir] ||
![file isdirectory [set permme "$idir/man[string range $dir 3 end]"]]} {
set permme $idir
}
file stat $permme dirstat
set perm [format "0%o" [expr {$dirstat(mode)&0777}]]
DEBUG { puts "\tsetting permission of directory $idir/$dir to $perm, from $permme" }
file attributes [file join $idir $dir] -permissions $perm
}
}
}
append idir "/$dir"
}

if {$saveerr ne ""} {
} elseif {![file writable $cat]} {
set saveerr "CAN'T SAVE: $cat not writable"
} else {
set path [set manx(catfull$w) [file join $cat $manx(man$w)]]
if {$manx(fBSDI)} {[set path [set manx(catfull$w) [file join $cat "[file rootname $manx(man$w)].0"]]]}

manWinstdout $w "Saving copy formatted by nroff ..." 1
foreach zapme [glob -nocomplain $path$manx(zoptglob)] {file delete -force $zapme}
DEBUG { puts "[manManPipe $manx(manfull$w)] | $man(format) > $path" }
set pipe "$format0 > $path"
if {[catch "exec $pipe" info]} {
set saveerr $info
} else {
catch {
file stat [file dirname $manx(manfull$w)] dirstat
set perm [format "0%o" [expr {$dirstat(mode)&0666}]]
DEBUG { puts "\tsetting permission of $path to $perm, from $manx(manfull$w)" }
file attributes $path -permissions $perm
}

if {[string match "*compress" $man(nroffsave)]} {
manWinstdout $w "Compressing ..." 1
set pipe "$man(compress) $manx(catfull$w)"
if {[catch "exec $pipe" info]} {
set saveerr "CAN'T COMPRESS:  $info"
} elseif {[file extension $cat] eq ".Z"} {	# H-P
file rename [glob $manx(catfull$w).$manx(zglob)] $manx(catfull$w)
set path $manx(catfull$w)
} else {
set path [set manx(catfull$w) [lfirst [glob $manx(catfull$w).$manx(zglob)]]]
}
}
set pipe [manManPipe $path]
}
}

if {$saveerr ne ""} {
DEBUG {puts "FORMATTING ERROR: $saveerr"}
after 20 manFormatError $w "{$pipe}" "{FORMATTING ERROR}" "{$saveerr}"
set path $manx(manfull$w)
set manx(catfull$w) ""
set pipe $format0
}

} else {
set path $manx(manfull$w)
set manx(catfull$w) ""
set pipe $format0
}

} elseif {[catch {[file readlink $manx(manfull$w)]}]} {
manWinstderr $w "$manx(manfull$w) is a symbolic link that points nowhere"
return
} else {
manWinstderr $w "$manx(manfull$w) not found"
return
}


set errflag 0
set msg [expr {[string match "*/*roff*" $pipe]?"Formatting and filtering":"Filtering"}]
manWinstdout $w "$msg $manx(name$w) ..." 1


append pipe " | $manx(rman) -f TkMan $manx(normalize) $man(subsect) $man(headfoot)"
if {$man(rebus)} {append pipe " -R $manx(rebus)"}
DEBUG {puts stderr "pipe = $pipe"}
PROFILE "opening pipe"

if {[catch {set fid [open "|$pipe"]} info]} {
after 20 manFormatError $w "{$pipe}" "ERROR" "{$info}"
DEBUG {puts "can't open pipe: $info"}
return
}

manTextOpen $w


fconfigure $fid -buffersize 102400
eval [read $fid]

if {[$t compare end < 3.0]} {
$t insert end "\nThis is a pretty short page.  Perhaps something's wrong with the formatting commands.\nType the following from a shell:\n\t$pipe\n\nIt should show man page text intermingled with Tcl/Tk commands.  (You can drop the '| rman ...' part to supress the Tcl/Tk commands.)  If not, change it so that it does--perhaps by tweaking an option in groff--and put the fix in the Makefile and/or the ~/.tkman startup file.\n"
}

while {[$t get 1.0] eq "\n"} {$t delete 1.0}
PROFILE "starting clo/pra/reb tags"
$t tag add man 1.0 end-1c; # handles single tab lines and leftovers
set cnt 1
foreach tabcnt $manx(tabcnts) {
if {$tabcnt>=2 && $tabcnt<=6} {$t tag add tab$tabcnt $cnt.0 "$cnt.0 lineend"}
incr cnt
}
foreach clo $manx(clo) {$t tag add clo $clo.0}
foreach para $manx(para) {$t tag add para1 $para.0}
foreach reb $manx(reb) {$t tag add reb $reb.0}

if {$man(wordfreq)} {$t insert 1.0 "\n"}


set rcsfile "[file dirname $frcs]/RCS/[file tail $frcs],v"
set rcscache "[file dirname $frcs]/RCSdiff/[file tail $frcs]"
if {$man(versiondiff) && [file readable $rcsfile]} {
catch {
set rlog [exec $man(rlog) $frcs]
set index [expr {$man(headfoot) eq ""? "end-1l" : "[lindex [$t tag ranges h2] end] linestart-1l"}]
$t insert $index "\n" "" "Revision History\n" h2 "\n[string trim $rlog]" "" "\n\n"
set rx {^revision ([0-9\.]+)}
while {[set index [$t search -regexp $rx $index+1l end]] ne ""} {
regexp $rx [$t get $index "$index lineend"] all rev
$t insert "$index lineend" "\t$frcs:$rev" {manref hyper}
}
}
}

PROFILE "finding bin"
if {!$isrcs && $man(headfoot) ne ""} {
set f $manx(manfull$w)

if {[catch {set og "[file attributes $f -owner]/[file attributes $f -group]"}]} {set og "(unknown)"}

$t insert end "[bolg $f ~], installed [textmanip::recently [file mtime $f]] by $og\n"
set binpre "executable: "; set binpost ""; set bincnt 0
set bin [file rootname $manx(name$w)]; # strip suffix
foreach bindir $manx(bin-paths) {
foreach path [glob -nocomplain $bindir/$bin $bindir/$bin-*] {
if {![file readable $path]} continue; # symbolic link to nowhere
if {[catch {set binog "[file attributes $path -owner]/[file attributes $path -group]"}]} {set binog "(unknown)"}

if {!$bincnt} {
if {[file mtime $manx(manfull$w)]+2*24*60*60 < [file mtime $path]} {
$t insert end "May be out of date with respect to executable\n" bi
}
}

set binvers ""
$t insert end "$binpre[bolg $path ~]$binvers, installed [textmanip::recently [file mtime $path]]"
if {$binog ne $og} {$t insert end " by $binog"}
$t insert end "$binpost\n"; incr bincnt

set binpre "   also:  "; set binpost ""
}
}
set actvol [string index [file extension [zapZ $f]] 1]
if {$bincnt==0 && ($actvol==1 || $actvol==6 || $actvol==8)
&& ![string match "Intro*" $f] && ![string match "List*" $f]} {
$t insert end "No corresponding executable in PATH!" bi
set binalts ""
foreach bindir [concat $manx(aux-binpaths) "[file dirname [file dirname $f]]/bin" "[file dirname [file dirname [file dirname $f]]]/bin"] {
if {[llength [glob -nocomplain $bindir/$bin $bindir/$bin-*]]} {
append binalts ":$bindir"
}
}
if {$binalts eq ""} {
$t insert end "  This may be fine, but it is unusual for volume $actvol"
catch {$t insert end ", [lindex $manx(manTitleList) [lsearch $manx(manList) $actvol]]"}
} else {
$t insert end "  However, try appending \"" "" $binalts tt "\" to your " "" "PATH" sc
}
$t insert end ".\n"
}
$t insert end "\n"

PROFILE "end bin / meta data report"
set fc [zapZ [file tail $f]]
set fpagecnt [info exists pagecnt($fc)]
if {!$fpagecnt} {set pagecnt($fc) [list 0 [clock seconds] 0 0 [clock seconds]]}
foreach {times lasttime cksum nlines firsttime} $pagecnt($fc) break
set fnewdate [expr {[file mtime $f]>$lasttime}]
PROFILE "checksum"
if {!$fpagecnt || [llength $pagecnt($fc)]<=2 || $fnewdate} {
set curcksum 0
catch {set curcksum [lfirst [eval exec [manManPipe $manx(manfull$w)] | $man(cksum)]]}
} else {set curcksum $cksum}
PROFILE "end checksum"
if {!$fpagecnt} {
$t insert end "Reading $fc for " "" "first time" b "\n"
} else {
$t insert end "Read $fc  " "" $times b " [textmanip::plural $times time], last time " "" [textmanip::recently $lasttime] b "\n"

if {$fnewdate} {
if {$cksum ne $curcksum && (![file readable $rcscache] || [file size $rcscache]>1)} {
set txt "This manual page has changed since you last looked at it.  "
if {![file readable $rcsfile]} {
append txt "If you had an old version in RCS, I could SHOW you exactly how it has changed."
} elseif {!$man(versiondiff)} {
append txt "If you turn on Occasionals/Show version differences, version difference information will be incorporated into the page so you can see exactly what changed."
} else {
append txt "You can see exactly how by scrolling through the page or by choosing \"version changes\" from the arrow next to \"n lines\" at the bottom of the screen and clicking Search."
}
after 1000 manTextPlug $t js1 [list "$txt\n\n"] b
}
}
}
set pagecnt($fc) [concat [lrange $pagecnt($fc) 0 1] $curcksum [lrange $pagecnt($fc) 3 end]]

if {$manx(mondostats)} {after 2000 manMondostatsAfter $t $loadtime}
}

manTextClose $w
PROFILE "close text widget"
manWinstdout $w ""

catch {close $fid}


if {$so} {
set manx(manfull$w) $f0
set manx(man$w) [zapZ [file tail $f0]]
set manx(name$w) [file rootname $manx(man$w)]
}

PROFILE "collecting js*.* from h2,h3"
set sect 1
foreach {s e} [$t tag ranges h2] {$t mark set js$sect $s; incr sect}
if {$man(headfoot) ne ""} {
$t mark set endcontent js[incr sect -1]-1l; $t mark unset js$sect
$t tag add sc "endcontent+3l" "end"
}
set maxsect [expr {$sect-1}]
set lastsect 1; set subsect 0
foreach {s e} [$t tag ranges h3] {
set sect $lastsect; while {$sect<=$maxsect && [$t compare js$sect < $s]} {incr sect}
incr sect -1
if {$sect ne $lastsect} {set subsect 1} else {incr subsect}; set lastsect $sect
$t mark set js$sect.$subsect $s
}
PROFILE "end collect / start manShowManFoundSetText"

manShowManFoundSetText $w $t [bolg [zapZ $manx(manfull$w)] ~]
manYview $w

if {$manx(tryoutline$w) && [set tag $man(manref-show)] ne "never"} {
foreach {s e} [$t tag ranges manref] {nb $t $tag $s $e}
}


$t configure -state normal
if {$man(versiondiff) && $manx(normalize) eq "-N"} {
scan [time {set diffcnt [manVersion $w $t $f]}] "%d" msec
}

PROFILE "begin rebus"
set rx " ($manx(rebus))"
foreach {ls lsplus1} [$t tag ranges reb] {
set s $ls
set le "$ls lineend"
while {[set s [$t search -elide -regexp -nocase -count e $rx $s $le]] ne ""} {
set s "$s+1c"; incr e -1
if {[lsearch [$t tag names $s] manref]==-1} {
set name "[string tolower [$t get $s $s+${e}c]]Rebus"
$t delete $s $s+${e}c
$t image create $s -image $name
}
}
}
PROFILE "end rebus"

PROFILE "highlights"
manHighlights $w get
PROFILE "end highlights"

PROFILE "Notemarks"
set manx(nb-cache) {}
notemarks $w $t
PROFILE "end Notemarks"

manAutosearch $w $t 1.0; # no delay for first hunk (maybe show first page's, eliminating future jump)

after idle manSynargs $w $t
after idle manAutokey $t

if {$man(wordfreq)} "after 100 manWordfreqAfter $w $t"

PROFILE "tagDist"
$t configure -state disabled
manShowTagDist $w h2 3
manShowTagDist $w manref 1 [$t tag cget manref -foreground]
PROFILE "end tagDist"



manWinstdout $w ""
manWinstdout $w $manx(hv$w)

cd $tmpdir
if {$trylong} {file delete -force $manx(longtmp)}
manShowManStatus $w
set manx(lastman) $manx(manfull$w)

if {$manx(outlinesearch) ne ""} {
set hit ""; set js 1
foreach sectname $manx(sectname$t) {
if {[regexp -nocase $manx(outlinesearch) $sectname]} {
if {[regexp -nocase ^$manx(outlinesearch) $sectname]} {
set hit $js; break
} elseif {$hit eq ""} {set hit $js}
}
incr js
}
if {$hit ne ""} {manOutlineYview $t js$hit}
set manx(outlinesearch) ""
} elseif {$manx(subsearch) ne ""} {
set manx(search,string$w) $manx(subsearch)
$w.search.s invoke
set manx(subsearch) ""
}


return $manx(manfull$w)
}

proc manMondostatsAfter {t loadtime} {
global manx

PROFILE "start mondo stats"
set state [$t cget -state]; $t configure -state normal

$t insert end "\n\n"
scan [$t index end] "%d" numlines

$t insert end "search time: "
$t insert end [format %.2f [expr {$manx(searchtime)/1000000.0}]] [expr {$manx(searchtime)>600000? "b":""}]
$t insert end " sec in $manx(db-pagecnt) pages, load time: "
$t insert end [format %.2f [expr {$loadtime/1000000.0}]] [expr {$loadtime>1000000? "b":""}]
$t insert end " sec for [string length [$t get 1.0 end]] chars\n"

set manx(searchtime) 0; # in case load from dups or history

set sum 0; set csum 0
foreach tag {b i bi tt sc symbol h2 h3 manref} {
set ranges [$t tag ranges $tag]
set eol [llength $ranges]
if {$eol==0} continue
if {$tag eq "h2"} {incr eol -2} elseif {$tag eq "sc"} {incr eol -2}
set ranges [lrange $ranges 0 [expr {$eol-1}]]
foreach {start end} [$t tag ranges $tag] {
scan $start "%d.%d" junk s; scan $end "%d.%d" junk e
incr csum [expr {$e-$s}]
}
set cnt [expr {$eol/2}]; incr sum $cnt
$t insert end "$cnt $tag, "
}
$t delete end-3c end-1c
$t insert end ".   total=$sum tags, covering $csum characters\n"
$t insert end "averages: [format %.2f [expr {$csum/($sum+0.0)}]] characters/tag, "
set tpl [expr {$sum/($numlines+0.0)}]
$t insert end [format %.2f $tpl] [expr {$tpl>1.0? "b":""}]
$t insert end " tags/line"

$t configure -state $state
PROFILE "done mondo"
}



proc manWordfreqAfter {w t} {
global manx

set key "wordfreq,$manx(manfull$w)"
if {![info exists manx($key)]} {
PROFILE "wordfreq"
set manx($key) [join [lrange [textmanip::wordfreq [$t get 1.0 end]] 0 6] "    "]
PROFILE "end wordfreq"
}


manTextPlug $t 1.0 $manx($key) {sc nowrap}
}


proc manAutokey {t {s 1.0} {e end}} {
global man

if {[string trim $man(autokeywords)] eq ""} return
set rx "(^|\[ \t(:-\])($man(autokeywords))"
for {} {[set s [$t search -elide -nocase -regexp -- $rx $s $e]] ne ""} {append s "+1c"} {
$t tag add autokey "$s+1c wordstart" "$s+1c wordend"
}	
}


proc manSynargs {w t} {
global manx

PROFILE "start synopsis args in green"
set multiple [regexp "," [lfirst [split [$t get js1 js2] "-"]]]
set searchfor [file rootname $manx(name$w)]; set len [string length $searchfor]
if {[set inx [lsearch $manx(sectname$t) "Synopsis"]]!=-1} {
set now [lindex $manx(sectposns$w) $inx]; set next [lindex $manx(nextposns$w) $inx]

set syntrim "*\[\]()&.,\;: \t"
set syncnt 0
for {set s $now} 1 {set s $e} {
if {[set nextrange [$t tag nextrange i $s $next]] eq ""} break
foreach {s e} $nextrange break
set argname [string trim [$t get $s $e] $syntrim]
if {![info exists synargs($argname)]} {
set synargs($argname) ""
$t tag add synopsisargs $s $e; # first occurance only
incr syncnt
}
}
set s $now
for {set s $next} {$syncnt && [set nextrange [$t tag nextrange i $s end]] ne ""} {set s $e+1c} {
foreach {s e} $nextrange break
set name [string trim [$t get $s $e] $syntrim]
if {[info exists synargs($name)]} {
$t tag add synopsisargs $s $e; nb $t malwaysvis $s $e
unset synargs($name)
incr syncnt -1
}
}

if {$multiple && [set s [$t search -elide -- $searchfor $now $next]] ne ""} {
$t tag add synopsisargs $s [set e $s+${len}c]; nb $t malwaysvis $s $e
}
}
set cnt 0
set rx "\t$searchfor"
for {set s 1.0} {$cnt<5 && $multiple && [set s [$t search -elide -- $rx $s end]] ne ""} {set s $e} {
$t tag add synopsisargs $s [set e $s+1c+${len}c]
nb $t malwaysvis $s+1c $e
incr cnt
}
update idletasks
PROFILE "end synopsis args in green"
}


proc manFormatError {w pipe errmsg errinfo} {
set t $w.show
manWinstdout $w "$errmsg -- see bottom of page"
set state [$t cget -state]
$t configure -state normal
$t insert end "\n\n========== $errmsg ==========\n\n" b $errinfo b
$t insert end "\n\nThis error was caused by the pipe below.  To prevent this from happening in the future, debug the pipe in a shell, outside of TkMan, and update the " "" "manformat" tt " specification in TkMan's " "" "Makefile" tt " or the " "" "man(format)" tt " variable in " "" "~/.tkman" tt " , or even  the man page itself.  If the error message refers to non-ASCII characters or unbreakable lines, the problem is with with the page itself or " "" "nroff" tt ".\n\n" "" $pipe tt
$t configure -state $state
}



set manx(nb-cache) {}
proc notemarks {w t} {
global man manx stat

if {$manx(mode$w) ne "man"} return

if {$manx(nb-cache) ne ""} {
foreach {tag ranges} $manx(nb-cache) {
if {$ranges ne ""} {eval $t tag add $tag $ranges}
}
return
}


set fll [expr {$man(columns)>2*$manx(screencols)}]


foreach {s e} [$t tag ranges diffd] {
for {set i [expr {int($s)}]; set e [expr {int($e)}]} {$i<$e} {incr i} {
set diffd($i) 1
}
}

if {$manx(tryoutline$w) && $man(options-show) ne "never"} {
foreach {clos cloe} [$t tag ranges clo] {nb $t $man(options-show) $clos "$clos+5c"}
if {$man(options-show) eq "firstvis"} {
foreach now $manx(sectposns$w) next $manx(nextposns$w) {
if {[$t tag cget "area$now" -elide]!="1"} {$t tag remove $man(options-show) $now $next}
}
}
}

set alwaysex [string equal $man(manfill) "in entirety"]
set exsects {}
if {$manx(tryoutline$w) && [set tag $man(manfill-show)] ne "never"} {
foreach now $manx(sectposns$w) next $manx(nextposns$w) sect $manx(sectname$t) {
if {[$t tag cget "area$now" -elide]=="1"} {
foreach pat $man(manfill-sects) {if {[regexp -nocase $pat $sect]} {lappend exsects $now $next}}
}
}
}
set onlyonesect [expr {[llength $exsects]<=2}]

set winfoheight [winfo height $t]
foreach {now next} $exsects {
set ybot [lsecond [$t bbox endcontent]]; # end-1l?
if {$ybot eq "" && !$alwaysex} break

set maxl $manx(lcnt0$now); # don't include subsections
set effmaxl $maxl; if {$fll} {set effmaxl [expr {int($effmaxl*4)}]}

if {$ybot eq ""} {
set fit 0
} else {
set h [font metrics [expr {$tag eq "malwaysvis"? "textpro" : "peek"}] -linespace]
set fit [min $effmaxl [expr {int(($winfoheight-$ybot)/$h)}]]
}

if {$ybot ne "" && $onlyonesect && 
int(($winfoheight-$ybot)/$manx(page-fhscale)) >= $effmaxl} {
manOutline2 $t "" $now

} elseif {$fit>=$effmaxl-1 && $onlyonesect} {
if {$fll} {
nb $t $man(manfill-show) "$now+1l linestart" "$now+1l linestart+[expr {$fit*$manx(screencols)}]c"
} else {
$t tag add $man(manfill-show) "$now+1l linestart" "$now+${fit}l linestart"
}

} else {
set inx $now
set pcnt 0
while {[set inx [$t tag nextrange para1 $inx $next]] ne ""} {
set para($pcnt) [expr {int([lfirst $inx])}]
incr pcnt; set inx [lsecond $inx]
}
set para($pcnt) [expr {int([$t index $next])}]


set bcnt 0
for {set i 0} {$i<$pcnt} {incr i} {
if {[lsearch -regexp [$t tag names $para($i).1] {^(b|i|bi)$}]!=-1} {
set bpara($bcnt) $para($i); incr bcnt
}
}
set bpara($bcnt) $para($pcnt)
if {$bcnt>=5} {unset para; array set para [array get bpara]; set pcnt $bcnt}
DEBUG {puts "bcnt=$bcnt"}
catch {unset bpara}


set lcnt 0
set lpp 1; #if {1 || $ybot eq "" || !$pcnt || !$onlyonesect} {set lpp 1} else {set lpp [max 1 [expr $fit/$pcnt]]}
$t tag configure $tag -relief [expr {$lpp>1?"raised":"flat"}]

for {set p 0} {$p<$pcnt && ($alwaysex || $lpp+$lcnt<=$fit)} {incr p} {
set lc 0; set pn [expr {$para([expr {1+$p}])-1}]
for {set l $para($p)} {$l<$pn} {incr l} {
if {[$t bbox $l.0] ne "" || [info exists diffd($l)]} continue

if {!$fll} {
$t tag add $tag $l.0 $l.0+1l
incr lc
} else {
scan [$t index "$l.0 lineend"] "%d.%d" junk scrnc
set scrnl [min [expr {$lpp-$lc}] [max 1 [expr {($scrnc+$manx(screencols)-1)/$manx(screencols)}]]]
$t tag add $tag $l.0 $l.[expr {$scrnl*$manx(screencols)}]
incr lc $scrnl
}

if {$lc==$lpp} break
}
}
}
}


if {$manx(tryoutline$w)} {
foreach now $manx(sectposns$w) {
if {[set ybot [lsecond [$t bbox endcontent]]] eq ""} break
if {[$t tag cget "area$now" -elide]!="1"} continue

if {[expr {$winfoheight-$ybot}]<[expr {$manx(lcnt0$now)*$manx(page-fhscale)}]} break
manOutline2 $t "" $now
}
}

set cache {}; foreach tag $manx(show-ftags) {lappend cache $tag [$t tag ranges $tag]}
set manx(nb-cache) $cache
}

proc manAutosearch {w t startinx {endinx ""}} {
global man manx

foreach var {autosearchnb autosearch} {set $var [string trim $man($var)]}
if {$autosearch eq "" && $autosearchnb eq ""} return

if {$autosearchnb ne ""} {
set inx $startinx; if {$endinx eq ""} {set next [$t index $inx+200l]} else {set next $endinx}
set rx "\\m($autosearchnb)"
while {[set inx [$t search -regexp -nocase -forwards -count e -elide $rx $inx+1c $next]] ne ""} {
$t tag add autosearchtag "$inx+1c wordstart"; # wordstart puts mark on section head triangle, which it vanishes when opened, but that's ok
if {$manx(mode$w) ne "texi" && $manx(tryoutline$w) && $man(search-show) ne "never"} {
nb $t $man(search-show) $inx+1c $inx+1c+${e}c; # no lines of context for autosearch
}
}
}


if {$autosearch ne ""} {
set rx "\\m($autosearch)"
for {set inx $startinx} {[set inx [$t search -regexp -nocase -forwards -count e -elide $rx $inx+1c $next]] ne ""} {set inx "$inx+1c"} {
$t tag add autosearchtag "$inx+1c wordstart"
}
}

if {$endinx eq "" && [$t compare $next < end]} {after idle manAutosearch $w $t $next} else {manShowTagDist $w search}
}



proc nb {t tag start end {bcon 0} {fcon ""}} {
global man manx

if {$fcon eq ""} {set fcon $bcon}

if {$man(columns)<2*$manx(screencols)} {$t tag add $tag "$start linestart-${bcon}l" "$end lineend+1c+${fcon}l"; return}

if {$bcon==0} {set bcon 0.5}; if {$fcon==0} {set fcon 0.5}
set s "$start-[expr {int($manx(screencols)*$bcon)}]c"; set smin "$start linestart"; if {[$t compare $s < $smin]} {set s $smin}
set e "$end+[expr {int($manx(screencols)*$fcon)}]c"; set emax "$end lineend"
if {[$t compare "$s+$manx(screencols)c" > $e]} {set e "$s+$manx(screencols)c"}
if {[$t compare $e > $emax]} {set e $emax}
$t tag add $tag $s $e; # cut into middle of words to emphasize it's an excerpt
}


proc manShowRandom {w} {
global man manx mani manc high

expr {srand([clock clicks])}

set sect ""
set page TkMan

switch -exact $man(randomscope) {
all {
while 1 {
set sect [lindex $manx(manList) [expr {int(rand()*[llength $manx(manList)])}]]
if {[lsearch $manx(specialvols) $sect]==-1} break
}
while 1 {
set dir [lindex $mani($sect,dirs) [expr {int(rand()*[llength $mani($sect,dirs)])}]]
set page [lindex $manc($sect,$dir) [expr {int(rand()*[llength $manc($sect,$dir)])}]]
if {[llength $manc($sect,$dir)]<=3 || ![regexp -nocase {list|intro} $page]} break
}
}
shortcuts {
if {[llength $man(shortcuts)]==0} {manWinstderr $w "The shortcuts list is empty"; return}
set sect ""; # take from name
set page [lindex $man(shortcuts) [expr {int(rand()*[llength $man(shortcuts)])}]]
}
history {
if {[llength $manx(history$w)]==0} {manWinstderr $w "No pages seen: history empty"; return}
set sect ""; # have the full path
set page [lindex $manx(history$w) [expr {int(rand()*[llength $manx(history$w)])}]]
}
dups {
set len [llength $manx(manhits)]
if {$len<2} {manWinstderr $w "No pages in multiple matches list"; return}
set sect ""; # have the full path
set page [lindex $manx(manhits) [expr {int(rand()*$len)}]]
manShowManFound $page 1 $w
return
}
inpage {
set t $w.show
set manrefs [$t tag ranges manref]
if {[llength $manrefs]==0} {
set man(randomscope) all; manShowRandom $w; set man(randomscope) inpage
return
}
set sect ""; # take from name
set i [expr {int(rand()*[llength $manrefs]/2)*2}]
set page [$t get [lindex $manrefs $i] [lindex $manrefs [expr {1+$i}]]]
}
volume {
set sect $manx(lastvol$w)
if {[catch {set textlist $mani($sect,form)}] || [llength $textlist]<2} {manWinstderr $w "No last volume"; return}
set cnt 0
while 1 {
set i [expr {int(rand()*[llength $textlist]/2)*2}]
set page [lindex $textlist $i]; set tag [lindex $textlist [expr {1+$i}]]
if {$tag eq "manref"} break
if {$cnt<50} {incr cnt} else return
}
if {[llength $page]>1} {set page [lindex $page [expr {int(rand()*[llength $page])}]]}
}
}

manShowMan $page $sect $w
set manx(tmp-infomsg) [manWinstdout $w]

if {$manx(randomcont)} {after 1000 manShowRandom $w}
}



proc manPrint {w {printer ""}} {
global man manx stat env

if {[string trim $man(print)] eq ""} return

set t $w.show; set wi $w.info

set f [string trim $manx(manfull$w)]
if {$f eq "" || ![file exists $f]} return
set tail [zapZ [file tail $f]]; set name [file rootname $tail]; set sect [string range [file extension $tail] 1 end]
if {$sect eq ""} {regexp $manx(zdirsect) [file tail [file dirname $f]] all sect}

set tmp [manWinstdout $w]
manWinstdout $w "Printing $f ..." 1
set curdir [pwd]
set topdir [file dirname $f]
set printpipe "[manManPipe $f] | $man(print)"
if {[string match "*/man/sman*/*" $f]} {
set printpipe "/usr/lib/sgml/sgml2roff $f | $man(print)"
} elseif {[regexp -- $man(catsig) $topdir]} {
set printpipe [manManPipe $f]
if {[tk_messageBox -title "NO GUARANTEES" -message "No troff source.  Try to reverse compile cat-only page?" -icon question -type yesno -default yes] eq "yes"} {
set printpipe " | $manx(rman) -f roff -n $name -s $sect $man(subsect) | $man(print)"
} else {append printpipe " " $man(catprint)}
}
if {[regexp $man(catsig) $topdir] || [string match */man?* $topdir]} {
set topdir [file dirname $topdir]
}

catch {cd $topdir}
DEBUG {puts stderr "print pipe = $printpipe"}

if {[string trim $printer] ne ""} {
set env(PRINTER) $printer; set env(LPDEST) $printer
}
eval exec $printpipe
manWinstdout $w $tmp
cd $curdir
incr stat(print)
}
proc manReadSects {{w .man} {force 0} {msg "Building database ..."}} {
global man manx mani manc stat env hunk hunkcode

set wi $w.info

cursorBusy
manWinstdout $w $msg 1

catch {unset hunkcode hunk}
set manx(newmen) {}
set manx(hunkcnt) 0
set hunkcode(0) manReadRecentDone
if {$manx(hunkid) ne ""} {after cancel $manx(hunkid)}

set manx(manList) ""; set manx(manTitleList) ""; set manx(mandot) ""
set lastv ""
set total 0
catch {unset manc}
set manx(stray-warnings) ""

set buildtime [time {
foreach i $mani(manList) j $mani(manTitleList) {
set nowv [string index $i 0]
if {$nowv eq $lastv} {set more [string range $i 1 end]} else {set more " $i"}
set lastv $nowv
manWinstdout $w "[manWinstdout $w]$more" 1
if {[set cnt [manReadSection $i]]} {
lappend manx(manList) $i; lappend manx(manTitleList) $j
incr total $cnt
}
}
manReadSection MASTER
}]

cursorUnset
manWinstdout $w "Read $total pages"
set manx(db-pagecnt) $total

if {![llength $manx(manList)]} {
puts stderr "Can't find any man pages!"
puts stderr "MANPATH = $env(MANPATH)"
exit 1
}

set maxdir ""; set maxdirtime 0
foreach i $mani(manList) {
scan [manLatest $mani($i,dirs)] "%d %s" mstime msdir
set mani($i,update) $mstime
if {$maxdirtime<$mstime} {set maxdirtime $mstime; set maxdir $msdir}
}
set manx($man(glimpsestrays),latest) $maxdirtime


foreach i $manx(manList) {set mani($i,form) ""}

foreach i $manx(extravols) {
foreach {letter title msg} $i break
lappend manx(manList) $letter; lappend manx(manTitleList) $title
set mani($letter,form) $msg; set mani($letter,cnt) 0; set mani($letter,update) ""
}

manMakeVolList

set manx(hunkid) [after 1000 $hunkcode(0)]
}




proc manLatestMan {root} {

set men [glob -nocomplain "$root/man?*"]
if {$men eq ""} {
set men [glob -nocomplain "$root/*"]
}

return [manLatest $men]
}

proc manLatest {dirs} {
global mani

set max 0; set maxdir ""
foreach sub $dirs {
if {[file isdirectory $sub]} {
set mtime [file mtime $sub]
set mani($sub,update) $mtime
if {$mtime>$max} { set max $mtime; set maxdir $sub }
}
}

return [list $max $maxdir]
}




proc manReadRecent {sect files recentdef hunknext} {
global manx hunk hunkcode

foreach f $files {
catch {
if {![regexp "$manx(bkupregexp)\$" $f] && [file mtime $f]>$recentdef && [file isfile $f]} {
lappend hunk($sect) [zapZ [file tail $f]]
}
}
}

set manx(hunkid) [after 100 $hunkcode($hunknext)]
}

proc manReadRecentDone {} {
global manx hunk

DEBUG {puts "RECENT DONE, hunk array: [array names hunk]"}
foreach n [array names hunk] {
if {$hunk($n) ne ""} {lappend manx(newmen) [list $n [lsort $hunk($n)]]}
}

.vols entryconfigure "Recently*" -state normal -label "Recently added/changed"
set manx(hunkid) ""
}



proc manReadSection {n} {
global man manx mani manc hunk hunkcode env

if {![llength $mani($n,dirs)]} {return 0}
set zbkup " \[^ \]+$manx(bkupregexp) "
set znodot { [^ \.]+ } 
set zsect {\.[^\. ]* }
set ztclmeta {([][{}"])}


DEBUG { puts -nonewline stderr $n }
set first 1

set recentdef [expr {[clock seconds]-$man(recentdays)*24*60*60}]

set hunksize 25
foreach i $mani($n,dirs) {
set dirtime [file mtime $i]
if {$dirtime>$recentdef} {
set mtimeme [glob -nocomplain $i/*]
set hunk($n) {}
for {set j 0} {$j<[llength $mtimeme]} {incr j $hunksize} {
set hunknow $manx(hunkcnt); set hunknext [incr manx(hunkcnt)]
set hunkcode($hunknext) $hunkcode($hunknow)

set hunkcode($hunknow) "manReadRecent $n [list [lrange $mtimeme $j [expr {$j+$hunksize-1}]]] $recentdef $hunknext"
}
}
}

set cnt 0
foreach i $mani($n,dirs) {
if {$manx(canformat)} {
cd $i; set men " [glob -nocomplain *] "
} else {
set men ""
}

regsub -all $manx(zregexpl) $men {\1 } men
while {[regsub -all $zbkup $men " " men]} {}
while {[regsub -all $znodot $men " " men]} {}

regsub -all $zsect $men " " men

regsub -all $ztclmeta $men {\\\1} men


set cat ""
if {[regsub {/man([^/]+)$} $i {/cat\1} d2] && [file isdirectory $d2] && [file readable $d2]} {
cd $d2; set cat " [glob -nocomplain *] "
regsub -all $manx(zregexpl) $cat {\1 } cat
while {[regsub -all $zbkup $cat " " cat]} {}
while {[regsub -all $znodot $cat " " cat]} {}
regsub -all $zsect $cat " " cat
regsub -all $ztclmeta $cat {\\\1} cat
set cat [lsort $cat]
}


set unique {}
set lastman ""
set cati 0; set catl [llength $cat]
set strays {}

if {!$manx(canformat)} {
foreach k $cat {if {[regexp {\.} $k]} {lappend manx(mandot) $k}}
set unique $cat
} else {
foreach k [lsort $men] {
while {$cati<$catl && [string compare [set kt [lindex $cat $cati]] $k]==-1} {
lappend strays $kt
lappend unique $kt
if {[regexp {\.} $kt]} {lappend manx(mandot) $kt}
incr cati
}
while {[lindex $cat $cati] eq $k} {incr cati}

if {$k eq $lastman} continue
lappend unique $k
if {[regexp {\.} $k]} {lappend manx(mandot) $k}
set lastman $k
}
}

set manc($n,$i) $unique
if {[llength $strays]} {
if {$manx(stray-warnings) eq ""} {set manx(stray-warnings) "Stray cats (formatted pages in .../man/catN without corresponding source in .../man/manN)\n"}
append manx(stray-warnings) "$d2\n\t$strays\n"
}

incr cnt [llength $unique]
}

return $cnt
}




proc manShowSection {w n} {
global man manx mani high stat
global bmb

if {[lsearch $manx(manList) $n]==-1} { manWinstderr $w "Volume $n not found"; return }
if {$manx(shift)} { set manx(shift) 0; set w [manInstantiate] }
set t $w.show; set wi $w.info

manNewMode $w section $n; incr stat(section)
set manx(lastvol$w) $n
set manx(hv$w) $n
manShortcutsStatus $w

set head [lindex $manx(manTitleList) [lsearch $manx(manList) $n]]

if {$mani($n,form) eq ""} {
cursorBusy
manWinstdout $w "Formatting $head ..." 1
set mani($n,shortvolname) [manFormatSect $n]
cursorUnset
}

set info $head
manWinstdout $w $info
manSetSect $w $n

manTextOpen $w
foreach {txt tag} $mani($n,form) {$t insert end $txt $tag}
manLineCnt $w $mani($n,cnt) "entries"
manTextClose $w

manYview $w
if {[lsearch {apropos high census} $n]!=-1} { set tag $n } else { set tag volume }
$t tag add $tag 1.0 end

$w.vols configure -text $mani($n,shortvolname); set bmb($w.vols) "manShowSection $w $n"
set manx(name$w) $head

set mod [expr {$man(hyperclick) eq "double"? "Double-" : ""}]
set ev "<${mod}ButtonRelease-1>"
if {$n eq "glimpse"} {
$t tag bind hyper $ev "+if {\$manx(glimpse-pattern) eq \$manx(search,string$w)} {$w.search.s invoke}"
} elseif {$n eq "glimpseindex"} {
$t tag bind hyper $ev "+
if {\$manx(hotman$t)!={}} { incr stat(man-hyper); manGlimpse \$manx(hotman$t) -w \$manx(out$w) }
"
}
}


proc manFormatSect {n} {
global man manx mani manc high pagecnt

set form {}; set cnt 0

if {$n eq "high"} {
lappend form "\tTime of last annotation\n" {}
set lastletter ""; set lastday ""
set sortedlist {}
if {$manx(highsortby)==0} {
foreach name [lsort -command manSortByTail [array names high]] {
set sec [lindex $high($name) 0]; if {[llength $sec]>1} {set time 0}
lappend sortedlist [list $name $sec]
}
} else {
set tuples {}
foreach name [array names high] {
set sec [lindex $high($name) 0]; if {[llength $sec]>1} {set time 0}
lappend tuples [list $name $sec]
}
set sortedlist [lsort -integer -index 1 -decreasing $tuples]
}
foreach k $sortedlist {
foreach {name sec} $k break

if {$manx(highsortby)==0} {
set letter [string tolower [string index [file tail $name] 0]]
if {$letter ne $lastletter} {lappend form "$letter  " h2; set lastletter $letter}
}
lappend form $name manref

regexp {(\d+:[\d:]+)*(.*)} [textmanip::recently $sec] all time day
if {$manx(highsortby)==1} {
if {$day eq $lastday} {set day ""} else {set lastday $day}
}
if {$sec>0} { lappend form "\t$time$day" i }
lappend form "\n" {}
incr cnt
}
set mani(high,cnt) $cnt
if {$mani(high,cnt)==0} {set form [list "No manual pages have been annotated.\n" b]}

set mani(high,form) $form
return "Highlighted"

} elseif {$n eq "recent"} {
set first 1
foreach i $manx(newmen) {
foreach {vol names} $i {}
if {$first} {set first 0} else {lappend form "\n\n\n" {}}
if {[set index [lsearch $mani(manList) $vol]]!=-1} {
lappend form " Volume $vol, \"[lindex $mani(manTitleList) $index]\", updated at " {} [textmanip::recently $mani($vol,update)] i "\n\n" {}
} else { lappend form $vol {} "\n\n" {}}
lappend form [join $names "\t"] manref
incr cnt [llength $names]
}
set mani(recent,cnt) $cnt
if {$mani(recent,cnt)==0} {
lappend form "There are no manual pages less than $man(recentdays) [textmanip::plural $man(recentdays) day] old.\n" {}
lappend form "You can change the definition of `recent' in Preferences/Misc.\n"
}
set mani(recent,form) $form
return "Recent"

} elseif {$n eq "census"} {
lappend form "\tTimes read\tTime last read\n" {}

set cntlist {}
foreach name [array names pagecnt] {lappend cntlist [concat $name $pagecnt($name)]}
if {![set cnt [llength $cntlist]]} {
lappend form "You haven't seen any pages yet!\n"
} else {
set lastday ""
set type "-integer"; set sortdir "-decreasing"
if {$manx(censussortby)==0} {set type "-ascii"; set sortdir "-increasing"}
foreach tuple [lsort $sortdir $type -index $manx(censussortby) $cntlist] {
foreach {name seencnt lastread} $tuple break
regexp {(\d+:[\d:]+)*(.*)} [textmanip::recently $lastread] all time day
if {$manx(censussortby)==2} {
if {$day eq $lastday} {set day ""} else {set lastday $day}
}
lappend form $name manref "\t$seencnt\t" {} "$time$day" i "\n" {}
}
}
set mani($n,form) $form; set mani($n,cnt) $cnt
return [lindex {Alpha Frequency Chrono} $manx(censussortby)]

} elseif {$n eq "glimpseindex"} {
manGlimpseIndexShow
return "Index"
}

if {$n eq "all"} {set sect $man(manList)} else {set sect $n}
set ltmp {}
foreach subvar [manSearchArray $sect] {
append ltmp $manc($subvar) " "
}

if {$man(volcol) eq "0"} {set sep "   "} else {set sep "\t"}
set cnt 0

set pr ""; set pl ""
set sub {}
foreach ir [lsort $ltmp] {
set il [string tolower [string index $ir 0]]

if {$pl ne $il && [llength $sub]} {
lappend form [join $sub "\t"] manref "\n\n" {}
set sub {}
set pl $il
}
if {$pr ne $ir} {lappend sub $ir}
set pr $ir
incr cnt
}
lappend form [join $sub "\t"] manref

if {!$cnt} {lappend form "No man pages" b " in currently enabled paths.\nTry turning on some under the Paths pulldown menu." {}}
set mani($n,form) $form
set mani($n,cnt) $cnt

return "($n)"
}

proc manSortByTail {a b} {
return [string compare -nocase [file tail $a] [file tail $b]]
}



proc manMakeVolList {{recentok 0}} {
global man manx bmb

set m .vols
destroy $m; menu $m -tearoff no -font gui

if {$man(texinfodir) ne ""} {
$m add command -label "Texinfo" -command "manTextOpen \$curwin; texiTop \$man(texinfodir) \$curwin.show; \$curwin.show tag add volume 1.0 end; manTextClose \$curwin; \$curwin.vols configure -text Texinfo; set bmb(\$curwin.vols) {$m invoke Texinfo}"
}

if {$man(rfcdir) ne "" && [file exists [file join $man(rfcdir) "rfc-index.txt"]]} {
$m add command -label "Request for Comments (RFC)" -command {
manShowText $man(rfcdir)/rfc-index.txt
searchboxSearch {^\d\d\d\d} 1 1 rfcxref $curwin.show $curwin
if {![info exists rfcmap]} {
manWinstdout $curwin "Finding RFC directories (required first time only)..."
cursorBusy
foreach rfc [find $man(rfcdir) {[string match "rfc*.txt" $file]} {$depth<=2}] {
if [regexp "$man(rfcdir)(.*/rfc0*(\\d+).txt)" $rfc all dir rfcnum] {
set rfcmap($rfcnum) $dir
}
}
cursorUnset
manWinstdout $curwin "Request for Comment"
}
$curwin.vols configure -text "RFC"; set bmb($curwin.vols) "$curwin.vols.m invoke *RFC*"
}
}

set iapropos [lsearch -exact $manx(manList) "apropos"]; # this is disgusting

set ctr 0
foreach i $manx(manList) j $manx(manTitleList) {
set menu $m; set label "($i) $j"
if {[llength [lassoc $manx(extravols) $i]]} {set label $j} \
elseif {$man(subvols)} {
set l1 [string index $i 0]
set p [lsearch -exact $manx(manList) $l1]
set c [lsearch -glob $manx(manList) "$l1?*"]; if {$c>=$iapropos} {set c -1}

if {$p!=-1 && $c!=-1} {
set menu $m.$p
if {$ctr==$p} {set label "general"}

if {![winfo exists $menu]} {
menu $menu -tearoff no
$m add cascade -label "($i) [lindex $manx(manTitleList) $p]" -menu $menu
}
}
}

if {$i eq "census"} {
$menu add cascade -label $label -menu [set m2 .vols.seensortby]; menu $m2 -tearoff no
foreach {label index} {
"sort by frequency" 1   "sort chronologically" 2  "sort alphabetically" 0
} {
$m2 add command -label $label -command "set mani(census,form) {}; set manx(censussortby) $index; manShowSection \$curwin census; \$curwin.show see 1.0"
}
} elseif {$i eq "high"} {
$menu add cascade -label $label -menu [set m2 .vols.highsortby]; menu $m2 -tearoff no
foreach {label index} {
"sort chronologically" 1  "sort alphabetically" 0
} {
$m2 add command -label $label -command "set mani(high,form) {}; set manx(highsortby) $index; manShowSection \$curwin high; \$curwin.show see 1.0"
}
} else {
$menu add command -label $label -command "manShowSection \$curwin $i"
}
incr ctr
}
if {!$recentok} {$m entryconfigure "Recently*" -state disabled -label "Recently -- Available momentarily"}

catch {$m entryconfigure "*apropos*" -state disabled}
catch {$m entryconfigure "*glimpse*" -state disabled}

foreach win [lmatches ".man*" [winfo children .]] {
.vols clone $win.vols.m
set mb $win.vols; $mb configure -text "Volumes"; set bmb($mb) {}
}
manMenuFit $m
}

proc manCatClear {} {
global man manx

foreach dir $manx(paths) {
if {[string match "*/catman*" $dir]} continue

catch {eval file delete -force [glob $dir/cat*/*]}
}
manCatClearRecursive $man(fsstnddir)
}

proc manCatClearRecursive {dir} {
foreach f [glob -nocomplain $dir] {
if {[file isdirectory $f]} {manCatClearRecursive $f}
}
catch {eval file delete -force [glob $dir/*]}
}

set manx(manpath-warnings) ""

proc manManpathCheck {} {
global man manx env

set manx(manpath-warnings) ""
set manx(paths) {}
set manpatherr ""
set whatiserr 0
set glimpseerr 0
set glimpseuptodate 1
set pass 0
set homeman $env(HOME)/man
set needmyman [expr {[file readable $homeman] && [llength [glob -nocomplain $homeman]]>0}]


set manx(fBSDI) [file readable [set whatis "/usr/share/man/whatis.db"]]
set fDebian [expr {[file readable [set whatis "/usr/share/man/index.bt"]] || [file readable [set whatis "/var/cache/man/index.bt"]] || [file readable [set whatis "/usr/man/index.bt"]] || [file readable [set whatis "/var/catman/index.bt"]]}]
set fHPUX 0; if {!$manx(fBSDI) && !$fDebian} { set fHPUX [file readable [set whatis "/usr/lib/whatis"]] }


if {[file exists $man(fsstnddir)] && ![file writable $man(fsstnddir)]} {
append manx(manpath-warnings) "Backup cache directory $man(fsstnddir) not writable\n\n"
}


foreach root [split $manx(MANPATH0) $manx(pathsep)] {
if {$root eq "." || [string match "./*" $root] || [string match "../*" $root]} {
append manpatherr "$root ignored -- relative paths are incompatible\n"
continue
}
if {[string match "~*" $root]} {set root [glob -nocomplain $root]}
if {[string trim $root] eq ""} continue

if {[string match "/?*/" $root ]} {
append manpatherr "$root -- spurious trailing slash character (\"/\")\n"
set root [string trimright $root "/"]
}

if {$root eq $homeman} {set needmyman 0}

if {$root eq "/"} {
append manpatherr "$root -- root directory not allowed\n"
} elseif {[lsearch $manx(paths) $root]>=0} {
append manpatherr "$root -- duplicated path\n"
} elseif {[set tmp [manPathCheckDir $root]] ne ""} {
append manpatherr $tmp
} elseif {![string match "*/catman" $root] && ![llength [glob -nocomplain $root/$manx(subdirs)]]} {
append manpatherr "$root -- no subdirectories matching $manx(subdirs) glob pattern\n"
if {![string match "*/man" $root] && [llength [glob -nocomplain [file join [file dirname $root] $manx(subdirs)]]]} {
append manpatherr "    => try changing it to [file dirname $root]\n"
} elseif {[file exists [file join $root "man"]]} {
append manpatherr "    => try changing it to $root/man\n"
}

} else {
lappend manx(paths) $root
if {![info exists man($root)]} {set man($root) 1}
lappend manx(pathstat) $man($root)
set manx($root,latest) [lfirst [manLatestMan $root]]

if {!$manx(fBSDI) && !$fDebian && !$fHPUX} {
if {![file exists [set whatis [file join $root "windex"]]]} {
set whatis $root/whatis
}
}

if {![file exists $whatis]} {
append manpatherr "$root -- no `whatis' file for apropos\n"
if {!$whatiserr} {
append manpatherr "    => generate `whatis' with mkwhatis/makewhatis/catman\n"
set whatiserr 1
}
} elseif {![file readable $whatis]} {
append manpatherr "$whatis not readable\n"
} elseif {[file mtime $whatis]<$manx($root,latest)} {
append manpatherr "$whatis out of date\n"
}

if {$man(glimpse) ne ""} {
set g $root; if {$man(indexglimpse) ne "distributed"} {set g $man(glimpsestrays)}
set gi $g/.glimpse_index

if {$man(indexglimpse) eq "distributed" || $pass==0} {
if {![llength [glob -nocomplain "$g/.glimpse*"]]} {
append manpatherr "$g -- no Glimpse support\n"
if {!$glimpseerr} {
append manpatherr "    => try building Glimpse database (under Occasionals)\n"
set glimpseerr 1; set glimpseuptodate 0
}
} elseif {![file readable $gi]} {
append manpatherr "$g -- Glimpse index exists but not readable\n"
}
}

if {[file readable $gi] && [file mtime $gi]<$manx($root,latest)} {
append manpatherr "$root -- Glimpse index out of date\n"
}
}
}

incr pass
}

if {$needmyman} {append manpatherr "~/man -- not in MANPATH, which is unusual\n"}
if {$manpatherr ne ""} {
append manx(manpath-warnings) "Problems in component paths of MANPATH environment variable...\n" $manpatherr "\n"
}

if {![llength $manx(paths)]} {
if {$manx(manpath-warnings) ne ""} {puts stderr $manx(manpath-warnings)}
puts stderr "NO VALID DIRECTORIES IN MANPATH!\a"
exit 1
}
}

proc manPathCheckDir {dir} {
set warning ""

if {![file exists $dir]} {
set warning "doesn't exist"
} elseif {![file isdirectory $dir]} {
set warning "not a directory"
} elseif {![file readable $dir]} {
set warning "not readable\n    => check permissions"
} elseif {![file executable $dir]} {
set warning "not searchable (executable)\n    => check permissions"
} elseif {![llength [glob -nocomplain $dir/*]]} {
set warning "is empty"
}

if {$warning ne ""} {set warning "$dir -- $warning\n"}
return $warning
}



proc manDescDefaults {} {
global man manx mani env

manDescManiCheck return

if {[info exists env(LANG)]} {set langs [split [string trim $env(LANG)] ":"]} else {set langs ""}
foreach i $mani(manList) { set mani($i,dirs) {} }
foreach i $manx(paths) { set mani($i,dirs) {} }
set mani($man(glimpsestrays),dirs) {}
set curdir [pwd]

foreach i $manx(paths) {
cd $i
set alldirs [glob -nocomplain $manx(subdirs)]
foreach l $langs {
set alldirs [concat [glob -nocomplain $l*/$manx(subdirs)] $alldirs]; # localized go first!
}
foreach d [lsort -command bytypenum $alldirs] {
if {[string match "*/*" $d]} {
set lang "[file dirname $d]/"; set dir [file tail $d]
} else {set lang ""; set dir $d }
if {![regexp $manx(zdirsect) $dir all dirsig]} continue
if {[string match "cat*" $dir]} {set dirsig [file rootname $dirsig]}
set num [file rootname $dirsig]; set num1 [string index $num 0]

if {[lsearch -exact $mani(manList) $num]!=-1} {set n $num} else {set n $num1}

set pat "^[stringregexpesc $i]/${lang}(man|sman|cat)[stringregexpesc $dirsig]\$"
set dir $i/$d
if {(![string match "cat*" $d] || [lsearch -regexp $mani($i,dirs) $pat]==-1) && [manPathCheckDir $dir] eq "" && ![regexp {@\d+$} $dir]} {
lappend mani($i,dirs) $dir
lappend mani($n,dirs) $dir
}
}
}

cd $curdir
set manx(defaults) 1
}

proc bytypenum {a b} {
if {[string match "*/*" $a]} {set al [file dirname $a]; set a [file tail $a] } else {set al ""}
if {[string match "*.Z" $a]} {set as [file extension $a]; set a [file rootname $a] } else {set as ""}
set at [string range $a 0 2]
if {[string match "*/*" $b]} {set bl [file dirname $b]; set b [file tail $b] } else {set bl ""}
if {[string match "*.Z" $b]} {set bs [file extension $b]; set b [file rootname $b] } else {set bs ""}
set bt [string range $b 0 2]

if {$al ne $bl} {
if {$al eq ""} {return 1} elseif {$bl eq ""} {return -1} elseif {$al<$bl} {return -1} else {return 1}
} elseif {$at ne $bt} {
if {$at eq "sma" || ($at eq "man" && $bt eq "cat")} {return -1} else {return 1}
} elseif {$as ne $bs} {
if {$as eq ""} {return 1} else {return -1}
} else {
if {$a<$b} {return -1} else {return 1}
}

return 0
}



proc manDescMove {from to dirs} {manDesc move $from $to $dirs}
proc manDescDelete {from dirs} {manDesc delete $from "" $dirs}
proc manDescCopy {from to dirs} {manDesc copy $from $to $dirs}
set manx(mandesc-warnings) ""
proc manDescAdd {to dirs} {
global mani manx man

set manx(mandesc-warnings) ""
set warnings ""

manDescManiCheck
foreach d $dirs {
if {[set warnmsg [manPathCheckDir $d]] ne ""} {
append warnings $warnmsg
} else {
foreach t $to {lappend mani($t,dirs) $d}

DEBUG {puts "MANPATH for $d?"}
set mp $d
while {[string match "/*" $mp] && $mp ne "/"} {
if {[lsearch -exact $manx(paths) $mp]>=0} {
DEBUG {puts "\tyes, in $mp"}
lappend mani($mp,dirs) $d; break
} else {set mp [file dirname $mp]}
}
if {$mp eq "/"} { lappend mani($man(glimpsestrays),dirs) $d
DEBUG {puts "\tno, added to strays\n\t\tnow mani($man(glimpsestrays),dirs) =  $mani($man(glimpsestrays),dirs)"}
}
}
}


if {$warnings ne ""} {
if {![string match *manDescAdd* $manx(mandesc-warnings)]} {
append manx(mandesc-warnings) "Problems with manDescAdd's...\n"
}
append manx(mandesc-warnings) $warnings
}
}


proc manDesc {cmd from to dirs} {
global man manx mani

manDescManiCheck
if {$from eq "*"} {set from $mani(manList)}
if {$to eq "*"} {set to $mani(manList)}
foreach n [concat $from $to] {
if {[lsearch $mani(manList) $n]==-1} {
puts stderr "$cmd: Section letter `$n' doesn't exist."
exit 1
}
}

DEBUG {puts stdout "$cmd {$from} {$to} {$dirs}"}
foreach d $dirs {
foreach f $from {
set newdir {}
foreach fi $mani($f,dirs) {
if {[string match $d $fi]} {
if {$cmd eq "copy"} {lappend newdir $fi}
if {[regexp "copy|move" $cmd]} {
foreach t $to {if {$f ne $t} {lappend mani($t,dirs) $fi} else {lappend newdir $fi}}
}
} else {lappend newdir $fi}
}
set mani($f,dirs) $newdir
DEBUG {puts stdout $f:$mani($f,dirs)}
}
}
}

proc manDescAddSects {l {posn "end"} {what "n"}} {
global man mani

manDescManiCheck
if {[regexp "before|after" $posn]} {set l [lreverse $l]}
foreach i $l {
foreach {n tit} $i break
if {[lsearch $mani(manList) $n]!=-1} {
puts stderr "Section letter `$n' already in use; request ignored."
continue
}

if {$posn eq "end"} {
lappend mani(manList) $n
lappend mani(manTitleList) $tit

} elseif {$posn eq "before" || $posn eq "after"} {
if {[set ndx [lsearch $mani(manList) $what]]==-1} {
puts stderr "Requested $posn $what, but $what doesn't exist; request ignored"
continue
}
if {$posn eq "after"} {incr ndx}
set mani(manList) [linsert $mani(manList) $ndx $n]
set mani(manTitleList) [linsert $mani(manTitleList) $ndx $tit]

} elseif {$posn eq "sort"} {
lappend mani(manList) $n
set mani(manList) [lsort $mani(manList)]
set ndx [lsearch $mani(manList) $n]
set mani(manTitleList) [linsert $mani(manTitleList) $ndx $tit]
}

set mani($n,dirs) {}
}
}



proc manDescManiCheck {{action "exit"}} {
global man mani manx env

if {!$manx(manDot)} manDot

if {![info exists mani(manList)]} {
set mani(manList) $man(manList)
set mani(manTitleList) $man(manTitleList)

if {![info exists env(MANPATH)] || [string trim $env(MANPATH)] eq ""} {
puts stderr "You must set a MANPATH environment variable,\nwhich is a colon-separated list of directories in which\nto find man pages, for example /usr/man:/usr/share/man.\n(See the help page for an explanation of why\nalternatives to the MANPATH are a bad thing.)"
exit 1
}
set manx(MANPATH0) $env(MANPATH)

manManpathCheck

if {$action eq "return"} return
manDescDefaults
}
}



proc manDescSGI {patterns} {
global man manx mani


set paterrs 0
foreach pat $patterns {
foreach {mapto patlist} $pat {}

if {[lsearch -regexp $mani(manList) ".?$mapto"]==-1} {
puts stderr "no volume corresponding to $mapto mapping (patterns: $patlist)"
incr paterrs
}

foreach p $patlist {
foreach pat2 $patterns {
if {$pat eq $pat2} break
set mapto2 [lfirst $pat2]; set patlist2 [lsecond $pat2]
foreach p2 $patlist2 {
if {[string match $p2 $p]} {
puts stderr "pattern $p never reached -- $mapto2's $p2 precludes it"
incr paterrs
}
}
}
}
}

lappend patterns {"" {""}}
DEBUG {puts "mani(manList) => $mani(manList)"}

set catmen {}
foreach d $manx(paths) {
if {[string match "*/catman" $d]} {lappend catmen $d}
}
if {![llength $catmen]} {
puts stderr "No sneaky catman directories found in MANPATH:\n\t$manx(MANPATH0)"
return
}


set rcats $catmen; set catmandirs {}
for {set i 0} {$i<[llength $rcats]} {incr i} {
foreach f [glob -nocomplain [file join [lindex $rcats $i] "*"]] {
if {![regexp {/[^/]+\.[^/]+$} $f] && [file tail $f] ne "RCS" && [file tail $f] ne "RCSdiff" && [lsearch -exact $rcats $f]==-1 && [file isdirectory $f]} {
lappend rcats $f; lappend catmandirs $f
}
}
}

foreach dir $catmandirs {
if {[regexp {(catman|_man)$} $dir]} continue
set tail [file tail $dir]
set vol [file tail [file dirname $dir]]
if {![regexp "^(man|cat)" $vol]} {set vol $tail; set tail ""}

set volnum [string index $vol 3]

DEBUG {puts -nonewline "$dir ($vol:$tail ($volnum)) => "}
set matched 0
foreach pat $patterns {
foreach {mapto patlist} $pat break
foreach dp $patlist {
if {[string match "*$dp" $dir]} {
DEBUG {puts -nonewline "match on $dp => "}
set matched 1
if {[lsearch -exact $mani(manList) "$volnum$mapto"]!=-1} {
DEBUG {puts $volnum$mapto}
manDescAdd "$volnum$mapto" $dir

} elseif {[lsearch -exact $mani(manList) $mapto]!=-1} {
DEBUG {puts $mapto}
manDescAdd $mapto $dir

} elseif {[lsearch -exact $mani(manList) $volnum]!=-1} {
DEBUG {puts $volnum}
manDescAdd $volnum $dir

} else {
DEBUG {puts "can't place"}
}

break
}
}
if {$matched} break
}
DEBUG {if {!$matched} {puts "CAN'T MATCH\a\a"}}
}
}



proc manDescShow {} {
global man manx mani

manDescManiCheck
puts stdout "*** manDescShow"
foreach i $mani(manList) {
puts stdout $i:$mani($i,dirs)
}
}



proc texiRegionFind {t l start end point} {
set ws {[ \t]}
set close [$t search -regexp -elide -- "^@end$ws+${l}($ws+|\$)" $point $end]
if {$close eq ""} return
set tag [$t get "$close+5c wordstart" "$close+5c wordend"]

set rx "^@(end$ws+)?${tag}($ws+|\$)"; # also ended by another instance of same tag
set cnt -1
for {set open $close} {$cnt} {} {
set open [$t search -regexp -elide -backwards -count openlen -- $rx $open-1c $start]
if {$open eq ""} return; # unmatched tags do happen
if {[$t get $open+1c $open+5c] eq "end "} {incr cnt -1} else {incr cnt 1}
}
set arg [$t get $open+${openlen}c "$open lineend"]

$t delete $close "$close+1l"; $t delete $open "$open+1l"

return [list $tag $arg $open [$t index $close-1l]]
}




proc texiRevLineFindAll {t l start end} {
set alllines {}
set rx "^@${l}( |\$)"
while {[set end [$t search -backwards -regexp -elide -count startlen -- $rx $end $start]] ne ""} {
set tag [$t get "$end+1c wordstart" "$end+1c wordend"]
$t delete $end $end+${startlen}c
lappend alllines $tag [string trim [$t get $end "$end lineend"]] $end
}
return $alllines
}


proc texiTagFindAll {t l start end} {
set all {}

set orx "(^|@@|\[^@])@($l)\{"; set crx {[^@]@[a-z]+{|}}
while {[set open [$t search -regexp -elide -count openlen -- $orx $start $end]] ne ""} {
set opentxt [$t get $open $open+3c]
if {$opentxt eq "@@@"} {append open "+2c"; incr openlen -2
} elseif {[string index $opentxt 0] ne "@"} {append open "+1c"; incr openlen -1}
set openend "$open+${openlen}c"
set ocnt 1; set close $openend-1c
set closeadj ""
while {$ocnt} {
set newclose [$t search -regexp -elide -count insidelen -- $crx $close+1c $end]
if {$newclose eq ""} break else {set close $newclose}
set t3 [$t get $close-2c $close+1c]
if {[string index $t3 2] eq "\}"} {
if {[string index $t3 1] ne "@" || [string index $t3 0] eq "@"} {incr ocnt -1}
} else {incr ocnt; append closeadj "-${insidelen}c-1c"}
}
if {$ocnt} break; # not properly nested
set closeret [$t index $close]; if {[$t index "$open linestart"]==[$t index "$close linestart"]} {append closeret "-${openlen}c"}
lappend all [$t get $open+1c $openend-1c] $open [$t index $closeret$closeadj]

$t delete $close; $t delete $open $openend

set start $open
}

return $all
}

proc texiRevTagFindAll {t l start end} {
return [lreverse [texiTagFindAll $t $l $start $end] 3]
}



array set texidef {
deffn {findex category name arguments}
defun {findex "Function" name arguments}
defmac {findex "Macro" name arguments}
defspec {findex "Special Form" name arguments}
defvr {vindex category name}
defvar {vindex "Variable" name}
defopt {vindex "Option" name}
deftypefn {tindex category datatype name arguments}
deftypefun {tindex "Function" datatype name arguments}
deftypevr {vindex category datatype name}
deftypevar {vindex "Variable" datatype name}
deftypecv {vindex category class name}
deftypeivar {vindex "Instance Variable" class name}
defop {findex category class name arguments}
defmethod {findex "Method" class name arguments}
defp {tindex category name attributes}
}


array set texitrans {
"dots" "..."  "enddots" "... ."  "bullet" "\xb7"  "copyright" "\xa9"
"result" "=>"  "equiv" "=="  "error" "error-->"  "expansion" "==>"  "point" "-!-"
"print" "-|"   "result" "=>"   "minus" "-"  "sp" "\n"  "exclamdown" "\xa1"  "questiondown" "\xbf"
"AA" "\xc5"  "aa" "\xe5"  "AE" "\xc6"  "ae" "\xe6"  "O" "\xd8"  "o" "\xf8"  "OE" "OE"  "oe" "oe"
"pounds" "\xa3"
}
set texitrans(today) [clock format [clock seconds] -format "%d %B, %Y"]
set texitrans(regexp) [join [array names texitrans] "|"]

array set texiaccent {
`A "\xc0" 'A "\xc1" ^A "\xc2" ~A "\xc3" \"A "\xc4"
,C "\xc7"
`E "\xc8" 'E "\xc9" ^E "\xca" \"E "\xcb"
`I "\xcc" 'E "\xcd" ^I "\xce" \"I "\xcf"
barD "\xd0"
~N "\xd1"
`O "\xd2" 'O "\xd3" ^O "\xd4" ~O "\xd5" \"O "\xd6"
`U "\xd9" 'U "\xda" ^U "\xdb" \"U "\xdc"
'Y "\xdd"
`a "\xe0" 'a "\xe1" ^a "\xe2" ~a "\xe3" a-\" "\xe4"
,c "\xe7"
`e "\xe8" 'e "\xe9" ^e "\xea" e-\" "\xeb"
`i "\xcc" 'i "\xcd" ^i "\xee" i-\" "\xef"
bard "\xf0"
~n "\xf1"
`o "\xf2" 'o "\xf3" ^o "\xf4" ~o "\xf5" \"o "\xf6"
`i "\xf9" 'i "\xfa" ^e "\xfb" \"e "\xfc"
'y "\xfd" y-\" "\xfd"
}

proc texiMarkup {t start end {force 0}} {
global texi texidef texiaccent

cursorBusy

foreach per $texi(persistent) {upvar #0 ${per}$t $per}



foreach {tag s e} [texiRevTagFindAll $t "footnote" $start $end] {
set footnote [$t get $s $e]
$t delete $s $e
$t insert $s "*"
$t tag add superscript $s

$t mark set insert [set m [$t index $end-1l]]
$t insert insert " *$footnote\n"
$t tag add superscript $m+1c; $t tag add sc $m insert
}


foreach {tag ctnt s} [texiRevLineFindAll $t "(printindex|majorheading|heading|subheading|subsubheading|subtitle|author|center|vskip)" $start $end] {
switch -exact $tag {
printindex {
$t delete $s "$s lineend+1c"

$t mark set $ctnt insert
set txtindex {}; set lastletter ""; set icnt 0
foreach tuple $texiindex($ctnt) {
foreach {iname isect ifont} $tuple break
set curletter [string tolower [string index $iname 0]]
if {$curletter eq $lastletter} {
lappend txtindex "  " tt "/" "" "  " tt; incr icnt
if {$icnt==10} {lappend txtindex "\n" ""; set icnt 0}
} elseif {$lastletter ne ""} {lappend txtindex "\n\n " ""; set icnt 0}
lappend txtindex " $iname" [list texixref $ifont]
set lastletter $curletter
}
lappend txtindex "\n"

$t mark set insert $s; eval $t insert insert $txtindex; $t tag add index $s insert
}

vskip {$t delete $s "$s lineend"; $t insert $s "\n\n"}

majorheading -
heading -
subheading -
subsubheading {
$t tag add $tag $s $s+1l
}

subtitle -
author -
center {
if {[$t get $s+1l] ne " "} {$t insert $s+1l " "}
$t insert $s " "; $t tag add $tag $s $s+1l
}
}
}


set point $start
while 1 {
set tag ""
foreach {tag arg s e} [texiRegionFind $t {(quotation|display|example|smallexample|lisp|smalllisp|format|flushleft|flushright|def\S+)} $start $end $point] {set point $s}
if {$tag eq ""} break

switch -glob $tag {
quotation {
$t tag add $tag $s $e
}

def* {
if {[string match "def*index" $tag] || $tag eq "definfoenclose"} continue
$t insert $s "\n"

while 1 {
set spec $texidef($tag)
set inx 0; set category [lsecond $texidef($tag)]
if {$category eq "category"} {set category [lfirst $arg]; incr inx}
$t insert $s " " {} [lindex $arg $inx] code "  " {} [lrange $arg [expr {1+$inx}] end] i "\t$category"
$t tag add rmtab $s "$s lineend"

append s "+1l"
if {[$t get $s] eq "@" && [string match "def*" [set tag [$t get $s+1c "$s+1c wordend-1c"]]]} {
set arg [$t get "$s+1c wordend+1c" "$s lineend"]
$t delete $s "$s lineend"
} else {$t insert $s " \t"; break}
}
}

default {
if {[string match "flush*" $tag]} {set ichar " "} elseif {$tag eq "format"} {set ichar " "; set tag "r"} else {set ichar " \t"}
for {scan $e "%d" i; incr i -1} {$i>=$s} {incr i -1} {
$t insert $i.0 $ichar; # can't add $tag here too because want to pick up ALL existing tags
}
$t tag add $tag $s $e
if {[$t get $e] ne "\n"} {$t insert $e "\n"}
}
}
}

set point $start
while 1 {
set tag ""
foreach {tag type s e} [texiRegionFind $t "(.?table|multitable|itemize|enumerate)" $start $end $point] {set point $s}
if {$tag eq ""} break

set mt [string equal $tag "multitable"]; if {[string match "*table" $tag]} {set tag "table"}
set tabtag "list"
if {$mt} {
set tabtag "multitable[incr texi(multitablecnt$t)]"
set mttabs ""
set scrnw [expr {[winfo width $t]-20}]
if {[lfirst $type] eq "@columnfractions"} {
foreach fract [lrange $type 1 end] {lappend mttabs "[expr {int($scrnw*$fract)}]p"}
} else {
set frlen 0; foreach fract $type {incr frlen [string length $fract]}
set tabposn 0
foreach fract $type {
incr tabposn [expr {int($scrnw*[string length $fract]/$frlen)}]
lappend mttabs ${tabposn}p
}
lappend mttabs "[expr {$tabposn+100}]p"; # in case miscount columns
}
$t tag configure $tabtag -tabs $mttabs
} elseif {$tag eq "table"} {
set tabtag "table"

} elseif {$tag eq "itemize"} {
switch -glob -- $type {
@bullet* {set mark " \xb7\t"}
@minus* {set mark " -\t"}
default {set mark " $type"}
}
} elseif {$tag eq "enumerate"} {
set icnt 1
set format " %d.\t"
if {[regexp {\d+} $type num]} {set icnt $num} \
elseif {[regexp {[:alpha:]} $type letter]} {scan $letter "%c" icnt; set format " %c.\t"}
}

set needindent 0
set itemlinelen 0
for {scan $s "%d" i; scan $e "%d" ie} {$i<$ie} {incr i} {
set linetag [$t get $i.0 $i.5]; set ch [string index $linetag 0]
if {$mt && ($linetag eq "@item" || $linetag eq "@tab ")} {
$t delete $i.0 $i.5
if {$linetag eq "@tab "} {$t insert $i.0 "\t"}
$t insert $i.0 " "
set needindent 0
} elseif {$linetag eq "@item"} {
set ex [string equal [$t get $i.5] "x"]
$t delete $i.0 $i.6+${ex}c; # @item+space
set itemlen 0; if {!$ex} {set itemlinelen 0}
if {$tag eq "itemize"} {
if {[string trim [$t get $i.0 "$i.0 lineend"]] eq ""} {
$t delete $i.0 $i.0+1l; incr ie -1; #incr i -1; # preserves line end ("\n")
}
$t insert $i.0 $mark
} elseif {$tag eq "enumerate"} {
$t delete $i.0 $i.0+1l; incr ie -1
$t insert $i.0 [format $format $icnt]
incr icnt
} else {
scan [$t index "$i.0 lineend"] "%d.%d" junk itemlen
$t insert $i.0 "$type\{"
$t insert "$i.0 lineend" "\}\t"
if {$itemlinelen+$itemlen>12 && [$t get "$i.0+1l" "$i.0+1l+5c"] ne "@item"} {$t insert "$i.0+1l" " \t"}
}
if {$ex && [expr {$itemlinelen+$itemlen}]<50} {
if {$tag eq "table"} {$t delete $i.0-2c}
$t insert $i.0-1c ", "
$t delete $i.0-1c
incr i -1; incr ie -1
incr itemlinelen $itemlen
} else {$t insert $i.0 " "; set itemlinelen $itemlen}
set needindent 0
} elseif {$ch eq " " || $ch eq "\t"} {
$t insert $i.1 "   "; # nested list/table (tried ... $i.0 " \t")
} elseif {$ch eq ""} {
set needindent 1
} elseif {$needindent} {
$t insert $i.0 "\t"; # sole place where initial \t OK
set needindent 0
}
}

if {[$t get $ie.0] ne "\n"} {$t insert $ie.0 "\n"}
$t tag add $tabtag $s $ie.0
}


foreach {tag s e} [texiRevTagFindAll $t "sc|uref|email|samp|dmn|math|,|v|H|u|ubaraccent|underdot|dotaccent|ringaccent|tieaccent|udotaccent|dotless|TeX|xref|ref|pxref|inforef|$texienclose(enregexp)" $start $end] {
set txt [$t get $s $e]; $t delete $s $e

switch -exact $tag {

xref -
ref -
pxref -
inforef {
foreach {nodename xrefname topic infofile printedmanual} [split $txt ","] break
if {$tag eq "inforef"} {set tag "xref"}
set txt ""; if {$tag eq "xref"} {set txt "See "} elseif {$tag eq "pxref"} {set txt "see "}
$t insert $s "$txt$nodename"; $t tag add texixref $s+[string length $txt]c "$s+[string length $txt]c+[string length $nodename]c"
}

dmn -
math {$t insert $s $txt}

v -
, -
H -
ubaraccent -
underdot -
dotaccent -
ringaccent -
tieaccent -
udotaccent -
dotless -
u {
catch {set txt $texiaccent($tag$txt)}
$t insert $s $txt
}

sc {$t insert $s [string toupper $txt]; $t tag add sc $s "$s+[string length $txt]c"}
samp {$t insert $s "`$txt'"; $t tag add tt $s+1c $e+1c}
email -
uref {
foreach {uref ureftxt} [split $txt ","] break
$t insert $s "<$uref>"; $t tag add tt $s "$s+[expr {2+[string length $uref]}]c"
if {$ureftxt ne ""} {$t insert $s "$ureftxt "}
}
TeX {$t insert $s "TEX"; $t tag add subscript $s+1c}

default {
$t insert $s "[lfirst $texienclose($tag)]$txt[lsecond $texienclose($tag)]"
}
}
}



foreach {tag s e} [texiTagFindAll $t "asis|r|i|b|t|w|code|kbd|key|file|url|var|dfn|emph|strong|titlefont|subtitle|author|cite" $start $end] {$t tag add $tag $s $e}

set rx {@[{}@:.?!*"'`~^\s]}
for {set s $start-1c} {[set s [$t search -regexp -elide $rx $s+1c $end]] ne ""} {} {
set ch [$t get $s+1c]
switch -regexp $ch {
{\*} {
$t delete $s $s+2c
if {[$t compare $s != [list $s lineend]]} {$t insert $s "\n"}
$t insert $s+1c " "
}
: {$t delete $s $s+2c}
{["'`~^]} {
set txt [$t get $s+1c $s+3c]; $t delete $s $s+3c
catch {set txt $texiaccent($txt)}
$t insert $s $txt
}
default {$t delete $s}
}
}

if {$force} return

scan [$t index $start+1l] "%d" stop
for {scan [$t index $end-2l] "%d" i} {$i>$stop && [$t get $i.0] eq "\n"} {incr i -1} {$t delete $i.0}
for {scan [$t index $end-1l] "%d" i} {$i>$stop} {incr i -1} {
if {[string first [$t get $i.0] " \n"]==-1 && [string first [$t get $i.0-1l] "\n"]==-1} {$t insert $i.0-1c " "; $t delete $i.0-1c}
}
for {scan [$t index $start] "%d" i} {[$t get $i.0] eq "\n"} {incr i} {}
$t delete $start+1l $i.0

$t tag raise table

cursorUnset
}





set texilevelx(names) {chapter section subsection subsubsection}
array set texilevelx {
0 chapter 1 section 2 subsection 3 subsubsection
chapter 0 centerchap 0 unnumbered 0 appendix 0 chapheading 0
section 1 unnumberedsec 1 appendixsec 1
subsection 2 unnumberedsubsec 2 appendixsubsec 2
subsubsection 3 unnumberedsubsubsec 3 appendixsubsubsec 3
}

proc texiStruct {t type sectdelta name file byte} {
global texi texilevel texilevelx

set x [$t index end-1l]
set lev [expr {$texilevelx($type)+$sectdelta}]
if {$lev<0} {set lev 0}; if {$lev>3} {set lev 3} elseif {$lev<0} {set lev 0}
incr texilevel($lev)
set n $texilevel(0)
for {set i 1} {$i<=$lev} {incr i} {append n ".$texilevel($i)"}
for {set i [expr {$lev+1}]} {$i<4} {incr i} {set texilevel($i) 0}
$t insert end "$name\n" $texilevelx($lev)

set m "js$n"
$t mark set $m $x

return $m
}



proc texiProcess {t file {curnode "Front Matter"}} {
global texi texised texiimap texiifont texidef teximacro texitrans texilevelx man manx

foreach per $texi(persistent) {upvar #0 ${per}$t $per}
set sumbytes 0
set sectdelta 0
set broodrx {^@(\S+)\s*((\S+)\s*(\S+(\s+\S+)*)?)?}

set region "set|clear|ifset|end ifset|ifclear|end ifclear|ignore|end ignore|iftex|end iftex|tex|end tex|ifhtml|end ifhtml|include|macro|end macro"
set struct "node|chapter|centerchap|unnumbered|appendix|chapheading|section|unnumberedsec|appendixsec|subsection|unnumberedsubsec|appendixsubsec|subsubsection|unnumberedsubsubsec|appendixsubsubsec|titlepage|\[\[:lower:]]+index|def|bye|raisesections|lowersections|vtable|end vtable|ftable|end ftable|item|itemx"

set rx "^@($region|$struct)\\M"
set valuerx "(^|\[^@])@value{(\[^\}]+)}"
set commentrx "(^|\[^@])@(c|comment)\\M.*"

set realf [lfirst [glob -nocomplain $file$manx(zoptglob)]]
if {$realf eq "" || ![file readable $realf]} {return $sumbytes}
set fid [open "|[manManPipe $realf]"]
fconfigure $fid -buffersize 102400; # helps a tiny bit
set filecontents [read $fid]
close $fid

set on 1; set inmacro 0; set endsed ""; set inftable 0; set invtable 0
set lastbyte -1; set curmark ""
set byte 0
foreach line [split $filecontents "\n"] {
set linelen [string length $line]; incr linelen; # add newline back into count
set byte0 $byte
incr byte $linelen

regsub $commentrx $line {\1} line; # expensive but gotta do it
if {$inmacro} {
if {[string match "@end macro*" $line]} {
set teximacro($macroname) [list $macroargs $macrobody]
set inmacro 0; set macrobody ""
} else {append macrobody "\n$line"}
}
for {set vline $line} {[regexp -indices $valuerx $vline all junk vari]} {set vline [string range $vline [expr {[lsecond $all]+1}] end]} {
set var [string range $vline [lfirst $vari] [lsecond $vari]]
if {![info exists texiinfovar($var)]} {set texiinfovar($var) "*No value for $var*"}
}


if {[regexp $rx $line]} {

regexp $broodrx $line all type name arg1 arg2
set typename "$type $arg1"
if {$on} {
if {[info exists texised([set hit $typename])] || [info exists texised([set hit $type])]} {
set on 0; set endsed $texised($hit); continue
}
} else {
if {$endsed eq "end iftex" && [regexp $struct $type]} {
} else {
if {$type eq $endsed || $typename eq $endsed} {set on 1}
continue
}
}



switch -glob -- $type {
set { set texiinfovar($arg1) $arg2 }
clear {	catch {unset texiinfovar($arg1)} }
ifset {	if {![info exists texiinfovar($arg1)]} {set on 0; set endsed "end ifset"} }
ifclear { if {[info exists texiinfovar($arg1)]} {set on 0; set endsed "end ifclear"} }
macro {
}
end {
if {$arg1 eq "ftable"} {set inftable 0} elseif {$arg1 eq "vtable"} {set invtable 0}
}


node {
set nodename [string trim [lfirst [split $name ","]]]
set curnode $nodename
}

raisesections {incr sectdelta -1}
lowersections {incr sectdelta}

include {incr sumbytes [texiProcess $t $arg1 $curnode]}
printindex {lappend texi(printindexes) $arg1; lappend texi(printindex) $curmark}
synindex -
syncodeindex  {
set mapfrom "${arg1}index"
foreach i [array names texiimap] {	if {$arg1 eq $texiimap($i)} {set mapfrom $i; break}  }
set texiimap($mapfrom) $arg2
}
defindex {lappend texiimap(${arg1}index) $arg1; lappend texiifont(${arg1}index) "asis"}
defcodeindex {lappend texiimap(${arg1}index) $name; lappend texiifont(${arg1}index) "code"}
definfoenclose {
foreach {cmd before after} [split $name ","] break
set texienclose([string trim $cmd]) [list [string trim $before] [string trim $after]]
}
def* {
if {[string match "*x" $type]} {set type [string range $type 0 [expr {[string length $type]-1-1}]]}
set spec $texidef($type)
foreach {index category} $spec break
set inx [expr {[lsearch $spec "name"]-2+1}]; if {$category eq "category"} {incr inx}
set name [lindex $all $inx]
lappend texiindex($texiimap($index)) [list $name $curnode $texiifont($index)]
}

ftable {set inftable 1}
vtable {set invtable 1}
item - itemx {
if {$inftable} {lappend texiindex($texiimap(findex)) [list $name $curmark $texiifont(findex)]
} elseif {$invtable} {lappend texiindex($texiimap(vindex)) [list $name $curmark $texiifont(vindex)]}
}
*index {lappend texiindex($texiimap($type)) [list $name $curmark $texiifont($type)]}

default {
set skipbyte [expr {$byte0+$linelen}]
if {$type eq "titlepage"} {set type "chapter"; set name "Title Page"
} elseif {$type eq "centerchap"} {set type "chapter"}
if {[info exists texilevelx($type)] && $texilevelx($type)==0} {$t see end; update idletasks}

regsub -all -- {([^\{])---} $name {\1--} name
while {[regsub -all "(\[^@])@($texitrans(regexp)){}" $name {\1$texitrans(\2)} name]} {}
while {[regsub -all "(^|\[^@])@value{(\[^\}]+)}" $name {\1$texiinfovar(\2)} name]} {}
set name [subst -nobackslashes -nocommands $name]

if {$lastbyte!=-1} {lappend texix($curmark) [expr {$byte0-$lastbyte}]}
if {$type eq "bye"} break
set curmark [texiStruct $t $type $sectdelta $name $file $skipbyte]
set texix($curmark) [list $file $byte]; set texinode($curnode) $curmark
set lastbyte $skipbyte
}
}
}
}
if {$lastbyte!=-1 && $type ne "bye"} {lappend texix($curmark) [expr {$byte0-$lastbyte}]}

incr sumbytes $byte
return $sumbytes
}


proc texiCallback {t sect} {
global manx curwin

texiFault $t $sect

set next [lindex $manx(nextposns$curwin) [lsearch $manx(sectposns$curwin) $sect]]
manAutosearch [winfo parent $t] $t $sect $next; # if put in Fault then show up when prefetch and full text search.  here, repeat search every time open, but that's ok
manAutokey $t $sect $next

if {$next ne "endcontent" && $next ne ""} {after 100 texiFault $t $next}
}

proc texiFault {t sect} {
global texi manx texitrans curwin
foreach per {texix texiinfovar teximacro} {upvar #0 ${per}$t $per}; # maybe expand to $texi(persistent)

if {$texix($sect) eq ""} return
set next [lindex $manx(nextposns$curwin) [lsearch $manx(sectposns$curwin) $sect]]

set txtstate [$t cget -state]; $t configure -state normal

foreach {f s len} $texix($sect) break
set point "$sect linestart+1l"
if {$texi(lastfile$t) ne $f} {
cd $texi(cd$t)
set realf [lfirst [glob $f$manx(zoptglob)]]
set fid [open "|[manManPipe $realf]"]
fconfigure $fid -buffersize 102400
set texi(lastfilecontents$t) [read $fid]
close $fid
set texi(lastfile$t) $f
}


$t mark set endinsert $point

regsub -all {[][$"\\]} "\n[string trim [string range $texi(lastfilecontents$t) $s [expr {$s+$len-1}]]]\n\n" {\\&} tcltxt

set sot {(?n)^@}; set soet {(?n)^@end[ \t]+}; set eot {([^\w\n][^\n]*)?\n}; # not guaranteed to be in newline-sensitive mode for eot

set shorttxt ""
while 1 {
if {![regexp -indices -- "${sot}(ignore|iftex|tex|ifhtml|ifnotinfo|menu|ifset|ifclear)$eot" $tcltxt indices]} break
foreach {s0 s1} $indices break
foreach {tag arg} [string range $tcltxt [expr {$s0+1}] $s1] break
if {![regexp -indices -- "$soet$tag$eot" $tcltxt indices]} break
foreach {e0 e1} $indices break
if {$s1>$e0} break

append shorttxt [string range $tcltxt 0 [expr {$s0-1}]]

if {[regexp "ifset|ifclear" $tag]
&& ([string equal $tag "ifset"] ^ ![info exists texiinfovar($arg)])} {
set tcltxt "[string range $tcltxt $s1 [expr {$e0-1}]][string range $tcltxt $e1 end]"
} else {set tcltxt [string range $tcltxt $e1 end]}
}
append shorttxt $tcltxt; set tcltxt $shorttxt



while {[regsub -all "(?n)^@(ifinfo|end ifinfo|ifnottex|end ifnottex|group|end group|titlepage|end titlepage|ifnothtml|end ifnothtml|ifset|end ifset|ifclear|end ifclear|iftex|end iftex|tex|end tex|if html|end ifhtml|\[\[:lower:]]\[\[:lower:]]?index|def\[\[:lower:]]*index|node|unnumbered|finalout|lowersections|raisesections|null|need|sp|include|noindent|title|set|chapter|section|subsection|subsubsection|page|contents|shortcontents|summarycontents|top|footnotestyle|setchapternewpage|paragraphindent|nwnode|leftmargin|dircategory|dirindex|bye)$eot" $tcltxt "" tcltxt]} {}
while {[regsub -all "(^|\[^@])@(c|comment)$eot" $tcltxt {\1} tcltxt]} {}
regsub -all {([^@])@(refill|:)} $tcltxt {\1} tcltxt
regsub -all {([^@])@([.!? \t{}])} $tcltxt {\1\2} tcltxt


regsub -all -- {([^\{])---} $tcltxt {\1--} tcltxt; # ([^\{]) for @samp{---} exception
while {[regsub -all "(^|\[^@])@($texitrans(regexp)){}" $tcltxt {\1$texitrans(\2)} tcltxt]} {}
while {[regsub -all {(^|[^@])@value{([^\}]+)}} $tcltxt {\1$texiinfovar(\2)} tcltxt]} {}
while {[regsub -all {\m@tab\M} $tcltxt "\t" tcltxt]} {}

regsub -all {([^@])@(asis|r|i|b|t|w|code|kbd|key|file|url|var|dfn|emph|strong|titlefont|subtitle|author|cite){(|([^{}]*[^\{@]))}} $tcltxt {\1" "" "\4" \2 "} texttxt

eval $t insert \$point \"$texttxt\" \"\"
$t tag add area$sect $point-1c "$next linestart"

texiMarkup $t $point endinsert


$t tag add area$sect $point-1c "$next linestart"; # for stragglers--should be able to delete eventually
for {set sup $sect} {[regexp $manx(supregexp) $sup all supnum]} {set sup "js$supnum"} {
$t tag add areajs$supnum $point-1c "$next linestart"
}
set texix($sect) ""; incr texi(sectcnt) -1


$t configure -state $txtstate
}


set texi(persistent) {texiindex texinode texiinfovar texix texienclose texiback texiprintindex teximacro}
set texi(noenclose) {^XXXNOMATCHESXXX$}; # for legacy.  could set to ""

proc texiShow {t f dir {force 0}} {
global texi texised texiimap texiback texiifont texilevel texilevelx man manx
foreach per $texi(persistent) {upvar #0 ${per}$t $per}

cd [set texi(cd$t) [file dirname $f]]


set realf [lfirst [glob -nocomplain $f$manx(zoptglob)]]
if {$realf eq ""} {$t insert end "doesn't exist!" b; return
} elseif {![file readable $realf]} {$t insert end "not readable!" b; return
}

set sumbytes 0

foreach array [concat $texi(persistent) texiimap texiifont texised] {catch {unset $array}}

set cache [lfirst [glob -nocomplain [file join $dir "[file tail $f]$manx(zoptglob)"]]]
if {!$force && $cache ne "" && [file readable $cache] && [file mtime $cache]>[file mtime $realf] && [file mtime $cache]>$manx(mtime)} {
set fid [open "|[manManPipe $cache]"]; set src [read $fid]; close $fid
eval $src

} else {

array set texiimap {cindex cp findex fn vindex vr kindex ky pindex pg tindex tp}
array set texiifont {cindex asis findex code vindex code kindex asis pindex code tindex code}
for {set i 0} {$i<[llength $texilevelx(names)]} {incr i} {set texilevel($i) 0}
array set texised {"ignore" "end ignore" "iftex" "end iftex" "tex" "end tex" "ifhtml" "end ifhtml"}
set texi(printindexes) {}; set texi(printindex) {}

cursorBusy
set subtags {section subsection subsubsection}; # not chapter
foreach tag $subtags {$t tag configure $tag -elide 1}
scan [time {set sumbytes [texiProcess $t [zapZ [file tail $f]]]}] "%d" time
foreach tag $subtags {$t tag configure $tag -elide ""}
cursorUnset



foreach index [array names texiindex] {
if {[lsearch $texi(printindexes) $index]!=-1} {
set content {}
set last ""
foreach tuple [lsort -dictionary -index 0 $texiindex($index)] {
set entry [lindex $tuple 0]
if {$entry ne $last} {lappend content $tuple; set last $entry}
}
set texiindex($index) $content
} else {
DEBUG {puts "\tno printindex for $index (length = [string length $texiindex($index)])"}
unset texiindex($index)
}
}

if {![llength [array names texienclose]]} {set texienclose(enregexp) $texi(noenclose)
} else {set texienclose(enregexp) [join [array names texienclose] |]}

texiMarkup $t 1.0 end 1; # grr, embedded @code{...} bits

catch {file delete -force $cache}
if {$time<1.5*1000000} {
} elseif {![file writable $dir] || ($cache ne "" && [file exists $cache])} {
} else {
set cache $dir/[file tail $f]
set wfid [open $cache "w"]
puts -nonewline $wfid "\$t insert end"
set ms [lsort -dictionary [array names texix]]
foreach m $ms {
set level [regsub -all {\.} $m {\.} junk]; set tag $texilevelx($level)
puts -nonewline $wfid " [list [$t get [list $m linestart] [list $m lineend]]] $tag {\n} {}"
}
puts $wfid ""
foreach tag {code subscript} {
if {[llength [$t tag ranges $tag]]} {puts $wfid "\$t tag add $tag [$t tag ranges $tag]"}
}
puts $wfid "update idletasks"
puts $wfid "set texi(printindex) [list $texi(printindex)]"
foreach per $texi(persistent) {
puts $wfid "array set $per [list [array get $per]]"
}
puts $wfid "set line 1; foreach m \[lsort -dictionary \[array names texix\]\] {\$t mark set \$m \$line.0; incr line}"
puts $wfid "# $sumbytes bytes processed in $time msec on [clock format [clock seconds]]"
close $wfid

eval exec $man(compress) $cache &
}
}

set texi(sectcnt) [llength [array names texix]]

set texiback(files) {}
foreach sect [lsort -dictionary [array names texix]] {
foreach {file s l} $texix($sect) break
if {![info exists hit($file)]} {lappend texiback(files) $file; set hit($file) 1}
lappend texiback($file) [list $sect $s]
}
set texiback(filez) {}; foreach file $texiback(files) {lappend texiback(filez) [lfirst [glob $file$manx(zoptglob)]]}
foreach file $texiback(files) {lappend texiback($file) {bogussect 100000000}}

set texi(lastsearch$t) {}; set texi(searched$t) 0; set texi(lasthits$t) {}
set texi(multitablecnt$t) 0

return $sumbytes
}


set texi(texinfo,update) 0
proc texiDatabase {dir} {
global texi manx
set dirfile "$dir/dir.tkman"

if {![file exists $dirfile]} {return [list "$dirfile doesn't exist" b]}
if {![file readable $dirfile]} {return [list "$dirfile unreadable" b]}

if {[file mtime $dirfile]>$texi(texinfo,update)} {
set texi(texinfo,update) [file mtime $dirfile]
set form {}
set texi(texinfo,paths) {}
set texi(texinfo,names) {}
set texi(texinfo,desc) {}

set topregexp "^\\*\\s+(\[^:]+): \\((\[^\\)]+\\.(texi|texinfo|info.*))\\)(?:$manx(zregexp0))?\\.\\s+(.*)"

set cnt 0
set fid [open $dirfile]
while {![eof $fid]} {
gets $fid line
if {[regexp $topregexp $line all name f suffix Zignore desc]} {
if {$suffix eq "info"} {lappend form $f b "-- .info files are formatted text; you want .texi/.texinfo Texinfo " "" "source" i "\n" {}; continue}
set realf [lfirst [glob -nocomplain [zapZ $f]$manx(zoptglob)]]
if {![file exists $realf]} {lappend form $f "" " -- doesn't exist\n" b; continue
} elseif {![file readable $realf]} {lappend form $f "" " -- not readable\n" b; continue}

lappend form $name [list js$cnt manref hyper] "\t$desc\n" {}
lappend texi(texinfo,names) $name
lappend texi(texinfo,desc) $desc
lappend texi(texinfo,paths) $f
incr cnt
} else {lappend form "$line\n" {}}
}
close $fid
set texi(texinfo,form) $form
}
return $texi(texinfo,form)
}

proc texiTop {dir t} {
global texi curwin

set manx(hv$curwin) texitop; # for last scroll position

eval $t insert end [texiDatabase $dir]

if {[info exists texi(texinfo,form)]} {
set cnt 0
foreach f $texi(texinfo,paths) {
$t tag bind js$cnt <Button-1> "set manx(hotman$t) $f"
incr cnt
}
}
}


proc texiSearch {w} {
global man manx texiback texi
set MAXSECT 10

if {$man(gzgrep) eq ""} return
set t $w.show
upvar #0 texiback$t texiback texix$t texix

set pat $manx(search,string$w)
if {[string trim $pat] eq ""} return
if {$pat ne $texi(lastsearch$t)} {
foreach sect $texi(printindex) { texiFault $t $sect }
after 1000 "manWinstdout $w {Index and header search done; search again for full search.}"

set texi(searched$t) 0
set texi(lastsearch$t) $pat

return

} elseif {$texi(searched$t)} {
set secthits $texi(lasthits$t)

} else {

set ignorecase ""; if {[string is lower $pat]} {set ignorecase "i"}
cd [file dirname $manx(manfull$w)]

cursorBusy
set secthits {}
if {[catch {set hits [eval exec $man(gzgrep) -b$ignorecase $pat $texiback(filez) 2>/dev/null]} errinfo]} {
manWinstderr $w "ERROR: $errinfo"
return -code break
}

set lasthit ""
foreach hit [split $hits "\n"] {
regexp {(([^:]+):)?(\d+)} $hit all junk file b; zapZ! file
if {$file eq ""} {set file [lfirst $texiback(filez)]}; # only one file so grep doesn't report filename
set lastsect ""
foreach pair $texiback($file) {
foreach {sect s} $pair break
if {$s>$b} {
if {$lastsect ne "" && $lastsect ne $lasthit} {lappend secthits $lastsect}
set lasthit $lastsect
break
}
set lastsect $sect
}
}
cursorUnset
set texi(searched$t) 1
}
set texi(lastsearch$t) $pat; set texi(lasthits$t) $secthits

set newsecthits {}; foreach sect $secthits {if {$texix($sect) ne ""} {lappend newsecthits $sect}}

after 100 "foreach sect [list $secthits] {$t tag add $man(search-show) \"\$sect linestart\" \"\$sect lineend\"}"

foreach sect [lrange $newsecthits 0 $MAXSECT] {texiFault $t $sect}
if {[llength $newsecthits]>$MAXSECT} {
manWinstderr $w "Too many matches.  Showing many; search again to see more."
set manx(search,oldstring$w) ""; # so can keep searching for same thing and getting KWIC soon enough
}
}

proc texiXref {t} {
global texi
foreach per $texi(persistent) {upvar #0 ${per}$t $per}

set sect ""

set ref [string trim [eval $t get [$t tag prevrange texixref current]]]
if {[info exists texinode($ref)]} {
set sect $texinode($ref)
} else {
set inxes [array names texiindex]
for {set mark current} {$mark ne ""} {set mark [$t mark previous $mark]} {
if {[lsearch -exact $inxes $mark]!=-1} break
}
if {$mark eq ""} return; # fail

set centry [lfirst [$t tag prevrange texixref current+1c]]; set cmark [$t index $mark]
foreach {now next} [$t tag nextrange texixref $cmark] break
for {set off 0} {$now ne $centry} {incr off} {
foreach {now next} [$t tag nextrange texixref $next+1c] break
}

set sect [lsecond [lindex $texiindex($mark) $off]]
}



if {$sect ne ""} {
searchboxKeyNav C space 0 $t; # so C-x goes back to start
manOutline $t 0 $sect
}
}


proc texiClear {dir} {
global manx
catch {eval file delete -force [glob $dir/*.{texi,texinfo}$manx(zoptglob)]}
}



set bmb(menubutton-delay) 250
set bmb(type) ""
set bmb(after) ""
set bmb(relief) ""
set bmb(w) ""
set bmb(x) ""; set bmb(y) ""

proc buttonmenubutton {mb {cmd ""}} {
global bmb

if {[winfo class $mb] ne "Menubutton"} {error "$mb must be a menubutton"}

set bmb($mb) $cmd

bind $mb <Button-1> {if [catch {bmbB1Down %W %X %Y}] break}
bind $mb <B1-Motion> {if {$bmb(type) eq "button"} break}
bind $mb <ButtonRelease-1> {if [catch {bmbB1Up %W}] break}
}

proc bmbB1Down {w x y} {
global bmb

if {$::tk::Priv(postedMb) ne ""} {::tk::MbButtonUp $w; return -code break}
if {$bmb(type) ne ""} {return -code break}

set bmb(w) $w; set bmb(relief) [$w cget -relief]
set bmb(x) $x; set bmb(y) $y

if {$bmb($w) eq ""} {set bmb(type) ""; return}; # continue with menubutton bindings

set bmb(type) "button"
catch {[::tk::ButtonDown $w]}; # brute force: -repeatdelay on button only not menubutton
if {[$w cget -menu] ne "" && [[$w cget -menu] index end] ne "none"} {
set bmb(after) [after $bmb(menubutton-delay) bmbConvert]
}
return -code break
}

proc bmbB1Up {w} {
global bmb

if {$bmb(type) eq "button"} {bmbButtonUp $w} else {::tk::MbButtonUp $w}
set bmb(type) ""
if {$bmb(after) ne ""} {after cancel $bmb(after)}
set bmb(after) ""
$bmb(w) configure -relief $bmb(relief)
return -code break
}

proc bmbConvert {} {
global bmb

if {$bmb(type) eq ""} return
set ::tk::Priv(buttonWindow) ""; # clean up
set bmb(after) ""

$bmb(w) configure -relief $bmb(relief)
set bmb(type) ""; # give control over to the menu system
set ::tk::Priv(inMenubutton) $bmb(w)
::tk::MbPost $bmb(w) $bmb(x) $bmb(y)
$bmb(w) configure -relief sunken; # that's how Netscape does it
}

proc bmbButtonUp {w} {
global bmb

if {$w eq $::tk::Priv(buttonWindow)} {
set ::tk::Priv(buttonWindow) ""
if {[$w cget -state] ne "disabled"} {
uplevel #0 $bmb($w)
}
}
}



set manx(startuptime) [clock seconds]
set manx(reading) 0; set manx(startreading) -1
wm withdraw .; update idletasks





proc manShortcuts {w cmd} {
global man manx short

set me $manx(typein$w)

set modeok [lmatch {man txt texi} $manx(mode$w)]
if {$cmd ne "init" && (!$modeok || $manx(man$w) eq "")} return

set present [expr {[lsearch -exact $manx(shortcuts) $me]!=-1}]
if {$cmd eq "add" && !$present} {lappend manx(shortcuts) $me; set short($me) [clock seconds]
} elseif {$cmd eq "sub" && $present} {set manx(shortcuts) [lfilter $me $manx(shortcuts)]}

set m .shortcuts
$m delete 0 last
set len [llength $manx(shortcuts)]
set list $manx(shortcuts)
if {$man(shortcuts-sort)} {set list [lsort $list]}
if {$len} {
foreach i $list {
$m add command -label $i -command "incr stat(man-shortcut); manShowMan [list $i] {} \$curwin"
}
}

foreach win [lmatches ".man*" [winfo children .]] {manShortcutsStatus $win}
manMenuFit $m
}


proc manShortcutsStatus {w} {
global man manx
global bmb

set me $manx(typein$w)

set modeok [lmatch {man texi txt} $manx(mode$w)]
set present [expr {[lsearch -exact $manx(shortcuts) $me]!=-1}]
set b $w.stoggle
if {$modeok} {
if {$present} {set cmd "sub"; set text "-"
} else {set cmd "add"; set text "+"
}
$b configure -text $text; set bmb($b) "incr stat(page-shortcut-$cmd); manShortcuts $w $cmd"
} else {$b configure -text "x"; set bmb($b) ""}
}




proc manHotSpot {cmd t xy} {
global man manx curwin

set manchars {[ a-z0-9_.~/$+()-:<]}
set manx(hotman$t) ""


if {$cmd eq "clear"} {
$t tag remove hot 1.0 end
return
}


scan [$t index $xy] "%d.%d" line char
scan [$t index "$line.$char lineend"] "%d.%d" bozo lineend

$t tag remove hot 1.0 end


if {0 && $manx(mode$curwin) eq "man" && ([$t get [set cmdstart "$xy wordstart-1c"]] eq "-" || [$t get [set cmdstart "$xy wordstart"]] eq "-")} {
set skipe "\[]\[\t .,;:\{\}?\]"
scan [$t index $cmdstart] "%d.%d" line char
for {set c0 $char} {$c0>0 && ![regexp $skipe [$t get $line.$c0]]} {incr c0 -1} {}
incr c0;	# went one too far
scan [$t index "$xy wordend"] "%d.%d" line char
for {set cn $char} {$cn<$lineend && ![regexp $skipe [$t get $line.$cn]]} {incr cn} {}

if {[lsearch [$t tag names $line.$c0] "cmd"]==-1} {set toggle "add"} else {set toggle "remove"}
$t tag $toggle cmd $line.$c0 $line.$cn

selection own $curwin.man

return
}


set c [$t get $line.$char]
if {$c eq "("} {
if {$char>0 && [$t get $line.$char-1c]!=" "} {incr char -1} else {incr char}
} elseif {$c eq ")"} {
if {$char>0} {incr char -1}
}


set lparen 0; set rparen 0
set fspace 0

for {set cn $char} {$cn<=$lineend && [regexp -nocase $manchars [set c [$t get $line.$cn]]]} {incr cn} {
if {$c eq "("} {
if {!$lparen} {set lparen $cn} else break
} elseif {$c eq ")"} {
if {!$rparen} {set rparen $cn; incr cn}
break
} elseif {$c eq ":" && ([string is space [$t get $line.$cn+1c]] || [string is space [$t get $line.$cn-1c]])} {
break
} elseif {[string is space $c]} {
if {!$lparen && !$fspace && $cn<$lineend && [$t get $line.$cn+1c] eq "("} {set fspace 1} else break
}
}
incr cn -1

for {set c0 $char} {$c0>=0 && [regexp -nocase $manchars [set c [$t get $line.$c0]]]} {incr c0 -1} {
if {$c eq "("} {
if {!$lparen} {set lparen $c0} else break
} elseif {$c eq ")"} {
break
} elseif {$c eq ":" && ([string is space [$t get $line.$c0+1c]] || [string is space [$t get $line.$c0-1c]])} {
break
} elseif {[string is space $c]} {
if {$lparen==[expr {$c0+1}] && !$fspace} {set fspace 1} else break
}
}
incr c0

if {!$lparen^!$rparen} {
if {$lparen} {
if {$char>$lparen} {set c0 [expr {$lparen+1}]} else {set cn [expr {$lparen-1}]}
set lparen 0
} else {
incr cn -1
}

} elseif {$lparen && [lsearch $man(manList) [$t get $line.$lparen+1c]]==-1} {
if {$char>$lparen} {set c0 [expr {$lparen+1}]} else {set cn [expr {$lparen-1}]}
set lparen 0

} elseif {$lparen==[expr {$rparen-1}] && $lparen>0} {
set cn [expr {$lparen-1}]

} elseif {$lparen && $rparen && [$t get $line.$c0] eq "/"} {
incr c0
} 

while {$c0>0 && [lsearch {" "} [$t get $line.$c0]]>=0} {incr c0}
while {$cn>$c0 && [lsearch {. - , " "} [$t get $line.$cn]]>=0} {incr cn -1}


$t tag add hot $line.$c0 $line.$cn+1c
set hyper [string trim [$t get $line.$c0 $line.$cn+1c]]

set manx(hotman$t) $hyper
}


proc manInstantiate {} {
global stat manx

incr stat(instantiation)
incr manx(uid)
incr manx(outcnt)
set w [TkMan]
manOutput

return $w
}


proc manOutput {} {
global manx

set wins [lmatches ".man*" [winfo children .]]

set titleList {}
foreach i [lsort -dictionary $wins] {
set title "#[string range $i 4 end]"
if {$title eq "#"} {append title 1}
lappend titleList $title $i
}

set wincnt 0
foreach w $wins {
set mb $w.output; set m $mb.m
$m delete 0 last
set mcnt 0
foreach {label val} $titleList {
set newlabel [expr {$wincnt==$mcnt?"Output":"=>$label"}]
$m add radiobutton -label $label -variable manx(out$w) -value $val \
-command "$mb configure -text $newlabel"
incr mcnt
}
manMenuFit $m
if {![winfo exists $manx(out$w)]} {set manx(out$w) $w; $w.output configure -text "Output"}

incr wincnt
}

if {$manx(outcnt)==1} {
pack forget .man.output
} else {
foreach w $wins {pack $w.output -before $w.occ -padx 2 -side left -expand yes}
}
}



proc manFilecomplete {w} {
global manx

set t $w.show; set wi $w.info
set line $manx(typein$w)
set file [string trim [llast $line] "<"]
set posn [string last $file $line]

set ll [llength [set fc [filecomplete $file]]]

if {!$ll} {
manWinstderr $w "no matches"
return
} elseif {$ll>=2} {
set matches {}; foreach i $fc {lappend matches [file tail $i]}
if {[string length $matches]<50} {
manWinstderr $w [lrest $matches]
} else {
manTextOpen $w
$t insert end [lrest $matches]
manTextClose $w
}
set fc [lfirst $fc]
}

set manx(typein$w) [string range $line 0 [expr {$posn-1}]]$fc

$w.mantypein icursor end
$w.mantypein xview moveto 1
}



proc manNewMode {w mode {n {""}}} {
global man manx stat item2posn

catch {unset item2posn}
$w.c delete all
set manx(tryoutline$w) 0

set t $w.show
$t tag add area 1.0; $t tag configure area -elide 0

$w.high configure -foreground $man(buttfg) -background $man(buttbg) -font gui


set y [$t index @0,0]
if {[$t tag ranges lastposn]!=""} {
set y [$t index lastposn.first]
} elseif {[$t tag ranges spot]!="" && [$t bbox spot.first]!=""} {
set y [$t index spot.first]
} elseif {[info exists manx(cursect$t)] && [set csy area$manx(cursect$t).first]!="" && [$t tag ranges $csy]!="" && [$t compare $csy > $y]} {
set y $csy
}
while {[$t compare $y < end] && [$t get $y] eq "\n"} {append y "+1l"}
set manx(yview,$manx(hv$w)) [manPosn2OutnOff $t $y]

set manx(oldmode$w) $manx(mode$w)
set manx(mode$w) $mode
set manx(manfull$w) ""
set manx(catfull$w) ""
set manx(man$w) ""
set manx(name$w) ""
set manx(num$w) ""
set manx(tryoutline$w) 0


set manx(search,oldstring$w) ""
manLineCnt $w ""
searchboxKeyNav "" Escape 0 $t $w.info 0
after 5 selection clear $t

set manx(vect) 1
set manx(try) 0
set m $w.sections.m; eval destroy [winfo children $m]; $m delete 0 last
$t configure -cursor left_ptr



set high(0) disabled; set high(1) normal

set h $high([lmatch {man help info texi rfc} $mode]); $w.sections configure -state $h
set h $high([lmatch {man txt texi rfc help} $mode])
foreach i {high} {$w.$i configure -state $h}
if {$man(print)!=""} {set h $high([lmatch man $mode]); .occ entryconfigure "Kill Trees" -state $h}

manHyper $w $n
}


proc manPosn2OutnOff {t posn} {
global manx

if {[catch {scan [$t index $posn] "%d.%d" line char}]} return
for {set s $posn+2c} {$s!="" && ![string match "js*" $s]} {set s [$t mark previous $s]} {}
if {$s eq ""} {return "1/0.0"}

scan [$t index $s] "%d" basestartline
regexp {js(.*)} $s all basenum

return "$basenum/[expr {$line-$basestartline}].$char"
}


proc manHyper {w {n ""}} {
global man manx

set t $w.show

foreach i {"Double-" ""} {
foreach j {"" "Alt-" "Shift-"} {
$t tag bind hyper <${j}${i}ButtonRelease-1> "format nothing"
}
}

if {$man(hyperclick) eq "double"} {set mod "Double-"} else {set mod ""}
$t tag bind hyper <ButtonRelease-1> "
if {\$manx(hotman$t)!={}} { set manx(typein$w) \$manx(hotman$t) }
"
$t tag bind hyper <${mod}ButtonRelease-1> "+
if {\$manx(hotman$t)!={}} { incr stat(man-hyper); manShowMan \$manx(hotman$t) $n \$manx(out$w) }
"
$t tag bind hyper <Shift-${mod}ButtonRelease-1> "
if {\$manx(hotman$t)!={}} { incr stat(man-hyper); set manx(shift) 1; manShowMan \$manx(hotman$t) $n \$manx(out$w) }
"
$t tag bind hyper <Alt-${mod}ButtonRelease-1> "
if {\$manx(hotman$t)!={}} { set manx(typein$w) \$manx(hotman$t); manShowMan <\$manx(hotman$t) \$manx(out$w) }
"

}




proc manTextPlug {t posn args} {
set state [$t cget -state]; $t configure -state normal
eval $t insert $posn $args
$t configure -state $state
}

proc manTextOpen {w} {
global man manx

cursorBusy
set t $w.show
$t configure -state normal
$t delete 1.0 end
set manx(sectposns$w) ""
set manx(cursect$t) js1
foreach i [$t mark names] {if {$i!="insert"&&$i!="current"} {$t mark unset $i}}
foreach i [$t tag names] {if {[regexp {(area)?js\d*} $i]} {$t tag delete $i}}
$t mark set js1 1.0; $t mark gravity js1 left
}

proc manTextClose {w} {
set t $w.show

if {[$t get "end -2c"] eq "\n"} {$t delete "end -2c"}

$t tag add hyper 1.0 end

if {[lsearch [$t mark names] "endcontent"]==-1} {$t insert end " "; $t mark set endcontent end-1c}
$t configure -state disabled
cursorUnset
$t mark set xmark 1.0
}

proc manResetEnv {} {
global env man manx mani

set manpath {}
foreach i $manx(paths) {if {$man($i)} {append manpath :$i}}
set env(MANPATH) [string range $manpath 1 end]

foreach i $manx(manList) {
if {[lsearch $manx(specialvols) $i]==-1 || $i eq "all"} {set mani($i,form) ""}
}
}

proc manSetSect {w n} {
global manx mani

set manx(cursect$w) *

if {[regexp {^([A-Z]:)?/} $n]} {
set dir [file dirname $n]
foreach vol $mani(manList) {
if {[lsearch -exact $mani($vol,dirs) $dir]!=-1} {
set manx(cursect$w) $vol
return $vol
}
}

if {[regexp {\.(.)[^/\.]*$} $n all letter]} {
set manx(cursect$w) $letter
return $letter
}

} elseif {[set f [lsearch $manx(manList) $n]]!=-1} {
set manx(cursect$w) $n
}
return $n
}

proc manMenuFit {m} {
global man manx

if {[winfo class $m]!="Menu"} {puts stderr "$m not of Menu class"; exit 1}
if {[$m index last] eq "none"} return

set sh [winfo screenheight $m]

set ok 0
for {set i [expr {[lsearch $manx(sizes) $man(gui-points)]+1}]} {$i>=0} {incr i -1} {
set p [lindex $manx(pts) $i]
set f [spec2font $man(gui-family) $man(gui-style) $p]
$m configure -font $f; update idletasks
set mh [winfo reqheight $m]
if {$mh<$sh} {set ok 1; break}
}

if {!$ok} {
set ctr 0
while {[winfo reqheight $m]>=$sh} {
$m delete last; incr ctr; update idletasks
}
$m delete last; incr ctr
$m add command -label "($ctr too many to show)" -state disabled
}
}



proc manInit {} {
global man manx mani

if {$manx(init)} return

manReadSects
manResetEnv
set manx(init) 1
}



set manx(MAXLEVELS) 4


proc manShowManFoundSetText {w t key} {
global man manx


set alljs [lmatches "js*" [$t mark names]]
if {[llength $alljs]==0} {set alljs 1.0}
set manx(sectposns$w) [lsort -dictionary $alljs]
set manx(nextposns$w) [concat [lrange $manx(sectposns$w) 1 end] endcontent]
set manx(cursect$t) [lfirst $manx(sectposns$w)]


set manx(sectname$t) {}
if {$manx(mode$w) eq "texi"} {
if {$man(showsectmenu)} {set manx(sectname$t) [split [$t get [lfirst $manx(sectposns$w)] "[llast $manx(sectposns$w)] lineend"] "\n"]} else {set manx(sectname$t) ""}
foreach now $manx(sectposns$w) {set manx(lcnt$now) [set manx(lcnt0$now) 0]}
$t tag remove hyper 1.0 end
} else {
scan [$t index [lfirst $manx(sectposns$w)]] "%d" linenow
foreach now $manx(sectposns$w) next $manx(nextposns$w) {
lappend manx(sectname$t) [$t get $now "$now lineend"]
scan [$t index $next] "%d" linenext
set manx(lcnt$now) [set manx(lcnt0$now) [expr {$linenext-$linenow-1}]]
set linenow $linenext
}
$t tag remove hyper $now "$now lineend"
}

set manx(sectlevels$t) {}
$t configure -state normal
foreach now $manx(sectposns$w) next $manx(nextposns$w) secttxt $manx(sectname$t) {
lappend manx(sectlevels$t) [regsub -all {\.} $now {\.} junk]

for {set sup $now} {[regexp $manx(supregexp) $sup all supnum]} {set sup "js$supnum"} {
catch {incr manx(lcntjs$supnum) [expr {$manx(lcnt$now)+1}]}
}

set skip($now) 0

if {$manx(mode$w) eq "man" && $man(outline) ne "off" && ($manx(lcnt$now)<=2 || ($manx(lcnt$now)<=5 && $secttxt ne "Synopsis" && $secttxt ne "Files")) && [lsearch -glob $manx(sectposns$w) $now.*]==-1} {
set ss "$now linestart+1l"; set se "$now linestart+1l+$manx(lcnt$now)l"
set fNAME [string equal $secttxt "Name"]; # normalized by RosettaMan

if {[$t compare "$ss+[expr {$manx(screencols)*2}]c" > $se]} {
set utxt [$t get $ss $se]; regsub -all " +" $utxt "" txt; set txtlen [string length $txt]
if {$txtlen<$manx(screencols) || ($txtlen<$manx(screencols)*1.1 && $fNAME)} {
set skip($now) 1
set manx(lcnt$now) [set manx(lcnt0$now) 1]

$t insert "$now lineend" "  "
for {scan [$t index $se-1l] "%d" i} {[$t compare $i.0 > $now]} {incr i -1} {
while {[regexp "\[ \t\]" [$t get $i.0]]} {$t delete $i.0}
$t insert $i.0 " "; $t delete $i.0-1c; $t insert $i.0 "\n" elide
}

foreach {junk s} [$t tag nextrange h2 1.0] {}; append s "+3c"
while {[set x [$t search "  " $s 2.0]]!=""} {$t delete $x}


if {$fNAME} {$t tag add sc "$now linestart+7c" "$now lineend"}
}
}
}
}
$t configure -state disabled



set manx(tryoutline$w) [expr {$manx(mode$w) eq "texi" || ($man(outline) ne "off"
&& $manx(manfull$w) ne "_help" && [$t bbox endcontent] eq "")}]


set manx(hv$w) $key


if {$manx(tryoutline$w)} {
for {set i 0} {$i<$manx(MAXLEVELS)} {incr i} {set last($i) ""}

$t configure -state normal
foreach now $manx(sectposns$w) level $manx(sectlevels$t) secttxt $manx(sectname$t) {

if {!$skip($now)} {
set closed 1; set imagename "closed"
if {$manx(mode$w) eq "man" && ($man(outline) eq "allexp" || ([string match "allbut*" $man(outline)] && [regexp -nocase $man(outlinebut) $secttxt$manx(lcnt$now)]))} {set closed ""; set imagename "opened"}

set tags [$t tag names "$now linestart"]
$t image create "$now linestart" -image $imagename
foreach tag $tags {$t tag add $tag "$now linestart"}

if {$manx(lcnt$now)>0} {$t insert "$now lineend" "     $manx(lcnt$now)" sc}

$t tag configure area$now -elide $closed
$t tag add outline "$now linestart" "$now lineend"; # if +1l can click to area off the right
set lmar [expr {0.3*(1+$level)}]c; $t tag configure area$now -lmargin1 $lmar -lmargin2 $lmar
}

if {$level>0 && $manx(mode$w) eq "man"} {$t tag add alwaysvis "$now linestart" "$now lineend+1c"}

for {set j $level} {$j<$manx(MAXLEVELS)} {incr j} {
if {$last($j)!=""} {$t tag add area$last($j) "$last($j) lineend" "$now linestart"; set last($j) ""} else break
}
set last($level) $now
}

for {set j $level} {$j<$manx(MAXLEVELS)} {incr j} {
if {$last($j)!=""} {$t tag add area$last($j) "$last($j) lineend" "endcontent"} else break
}
$t configure -state disabled
}


foreach tag [concat $manx(show-tags) hyper elide] {$t tag raise $tag}



if {$man(showsectmenu)} {after 1000 manMakeSectMenuAfter $w $t}

after 100 focus $t
}

proc manMakeSectMenuAfter {w t} {
global man manx

set m [set mb $w.sections].m
if {$manx(tryoutline$w)} {
$m add command -label "Expand next/scroll" -accelerator "Return" -command "manDownSmart $w $t"
$m add command -label "Toggle current" -accelerator "Button 1 on header" -command "manOutline $t -1 \$manx(cursect$t)"
$m add command -label "Current + hierarchy" -accelerator "Shift-Button 1 on header" -command "manOutline $t -1 \$manx(cursect$t) 1"

set manx(texishowsubs) ""
if {$manx(mode$w) eq "texi"} {
$m add checkbutton -label "Show All Subsection Heads" -variable manx(texishowsubs) -onvalue 0 -offvalue "" -command "foreach tag {section subsection subsubsection} {$t tag configure \$tag -elide \$manx(texishowsubs); $t tag raise \$tag}; $t yview moveto 0"
if {[catch {$t index js2}] || [llength $manx(sectposns$w)]<40} {$w.sections.m invoke "last"}
}
$m add command -label "Collapse current" -accelerator "Button 3 anywhere" -command "manOutline $t 1 \$manx(cursect$t)"
$m add command -label "Collapse all" -accelerator "Double-Button 3" -command "manOutline $t 1 *; $t yview moveto 0; if {\$manx(mode$w) eq \"man\"} {notemarks $w $t}"
$m add separator
}


for {set i 0; set prefix ""} {$i<$manx(MAXLEVELS)} {incr i} {
set clevel($i) 0
set pfx($i) $prefix; append prefix "   "
}

foreach level $manx(sectlevels$t) {incr clevel($level)}

set showlevel 0
set scnt $clevel(0)
for {set i 1} {$i<$manx(MAXLEVELS)} {incr i} {
incr scnt $clevel($i)
if {$scnt>50} break
incr showlevel
}

set first 1
foreach now $manx(sectposns$w) txt $manx(sectname$t) level $manx(sectlevels$t) {
if {$level<=$showlevel} {
$m add command -label "$pfx($level)$txt" -command "incr stat(page-section); manOutlineYview $t $now"
if {$first} {$m entryconfigure last -command "incr stat(page-section); $t see 1.0"; set first 0}
}
}

if {$manx(mode$w) eq "man" && $man(headfoot) ne ""} {
$m add separator
$m add command -label "Header and Footer" -command "incr stat(page-section); $t yview endcontent"
}
configurestate $mb
after 500 manMenuFit $w.sections.m
}



proc manYview {w} {
global manx man

set t $w.show
if {[catch {set y $manx(yview,$manx(hv$w))}]} {set y "1/1.0"
} else {
regexp {(.*)/(.*)\.(.*)} $y all sect loff coff; set y "js$sect+${loff}l+${coff}c"
if {[$t index $y]!=1.0} {
if {$manx(tryoutline$w)} {nb $t lastposn $y $y} else {manOutlineYview $t $y}
}
}
$t mark set xmark [$t index @0,0]
}


proc manOutlineYview {t line} {
global man

if {[catch {set line [$t index $line]}] || [$t compare $line < 2.0]} return; # don't open top section when first show page
manOutline $t "" $line
$t yview $line-$man(high,vcontext)l
$t see $line
}

proc manOutlineSect {t sect} {
global manx curwin

if {[catch {set now [$t index $sect]}]} {return 0.0}
regexp {(.*)/(.*)} [manPosn2OutnOff $t $sect] all new junk
return "js$new"
}



proc manDownSmart {w t} {
global man manx stat

if {!$manx(tryoutline$w) || [lsearch {section apropos glimpse info} $manx(mode$w)]>-1 || [catch {$t index js1}]} {$t yview scroll 1 pages; return}
incr stat(page-downsmart)

set sect $manx(cursect$t)
if {[$t bbox $sect] eq ""} {
set sect [manOutlineSect $t @0,0]
if {[$t bbox $sect] eq ""} {
set sect [lindex $manx(sectposns$w) [expr {1+[lsearch $manx(sectposns$w) $sect]}]]
}
}

set x [lsearch $manx(sectposns$w) $sect]
while 1 {
set openme [lindex $manx(sectposns$w) $x]
if {$openme eq "" || [$t bbox $openme] eq ""} {
$t yview scroll 1 pages
break

} elseif {[$t tag cget area$openme -elide]=="1"} {

if {$man(tidyout)} {
set level [regsub -all {\.} $openme {\.} junk]; set curlevel 1000
for {set i [expr {$x-1}]} {$i>=0} {incr i -1} {
set cursect [lindex $manx(sectposns$w) $i]
set curlevel [regsub -all {\.} $cursect {\.} junk]
if {$curlevel<$level} {$t see $cursect; break}
manOutline2 $t 1 $cursect
}
}

manOutline $t 0 [set manx(cursect$t) $openme]
$t tag remove spot 1.0 end; $t tag add spot $openme

break
} else {incr x}
}

update idletasks
}



proc manOutline {t finv sect {prop 0}} {
global manx curwin

set time0 [clock clicks]

if {!$manx(tryoutline$curwin) || [string trim $sect] eq ""} return

set manx(hitlist$t) {}


if {$sect eq "*"} {set sect $manx(sectposns$curwin)}

if {[llength $sect]>1} {
foreach s $sect {manOutline $t $finv $s $prop}
return
} elseif {![string match "js*" $sect]} {
if {[catch {set now [$t index $sect]}]} return
set sect [manOutlineSect $t $sect]
}

set oldfinv [$t tag cget area$sect -elide]
if {$finv==-1} {
set finv [expr {$oldfinv==""?1:""}]
} elseif {$finv==0} {set finv ""}

if {$finv==""} { foreach tag $manx(show-ftags) {$t tag remove $tag 1.0 end} }

set sects $sect
if {$prop} {
set su $sect
if {$finv=="1"} {
while {[regexp $manx(supregexp) $su all sunum]} {lappend sects [set su "js$sunum"]}

} else {
set lev [regsub -all {\.} $sect {\.} junk]
foreach s [lrange $manx(sectposns$curwin) [expr {1+[lsearch $manx(sectposns$curwin) $sect]}] end] {
if {[regsub -all {\.} $s {\.} junk] <= $lev} break
lappend sects $s
}
}
}
foreach s $sects {manOutline2 $t $finv $s}

if {$finv!=1} {
$t yview [set manx(cursect$t) $sect]
if {[$t dlineinfo $sect-5l] eq ""} {$t yview scroll -5 units}
}

}


proc manOutline2 {t finv sect} {
global man manx curwin texix$t stat
upvar #0 texix$t texix

if {$finv!=1} {
if {[regexp $manx(supregexp) $sect all num]} {manOutline2 $t $finv "js$num"}
}
if {[lsearch $manx(sectposns$curwin) $sect]==-1 || [lsearch -exact [$t tag names $sect] outline]==-1} return

set oldfinv [$t tag cget area$sect -elide]
if {$finv==$oldfinv} return

$t tag configure area$sect -elide $finv
set txtstate [$t cget -state]
$t configure -state normal
$t image configure "$sect linestart" -image [expr {$finv==1?"closed":"opened"}]
$t configure -state $txtstate
if {$finv==1} {incr stat(outline-collapse)} else {incr stat(outline-expand)}

if {$finv!=1 && $manx(mode$curwin) eq "texi"} {
cursorBusy 0
texiCallback $t $sect; # use anchored points to ease bookkeeping for texiMarkup
cursorUnset
scan [$t index end-1c] "%d" lastline 
manLineCnt $curwin $lastline; # counts \n-terminated lines, sigh
}
}


proc manLineCnt {w cnt {unit ""}} {
global man manx

if {$cnt==""} {$w.search.cnt configure -text ""; return}

if {$unit==""} {
if {$man(lengthchunk) eq ""} return;	# no report
set unit [textmanip::plural $cnt $man(lengthchunk)]
set cnt [expr {1+int($cnt/$manx($man(lengthchunk)-scale))}]
}
$w.search.cnt configure -text "$cnt $unit"
}


proc manManPipe {f} {
global man manx

if {[regexp $manx(zregexp) $f] || [regexp $manx(zregexp) [file dirname $f]]} {
set pipe $man(zcat)
} else {set pipe "cat"}

return "$pipe $f"
}

proc manShowManStatus {w} {
global man manx pagecnt

set t $w.show; set wi $w.info


manSetSect $w $manx(manfull$w)

set manx(typein$w) $manx(name$w)
$w.mantypein icursor end

set manx(history$w) \
[lrange [setinsert $manx(history$w) 0 [list $manx(manfull$w)]] 0 [expr {$man(maxhistory)-1}]]
set m [set mb $w.history].m
$m delete 0 last
$m post 0 0; $m unpost; # needed to compensate for Tk menu bug
foreach i $manx(history$w) {
if {[llength [lfirst $i]]>=2} {set l [lfirst $i]} else {set l $i}
if {![regexp {^[|<]} $l]} {set l [zapZ [file tail $l]]}
$m add command -label $l -command "incr stat(man-history); manShowMan $i {} $w"
}
configurestate $mb
manMenuFit $m


manShortcutsStatus $w


scan [$t index end] "%d" linecnt 
manLineCnt $w $linecnt

set f [zapZ $manx(manfull$w)]
if {![string match "<*" $f]} {set f [file tail $f]}
if {![info exists pagecnt($f)]} {set pagecnt($f) [list 0 0 -1 0 [clock seconds]]}

foreach {times lasttime cksum nlines firsttime} $pagecnt($f) break
if {$firsttime==""} {set firsttime [clock seconds]}
if {$cksum==""} {set cksum -1}
set pagecnt($f) [list [expr {1+$times}] [clock seconds] $cksum $linecnt $firsttime]
}


proc zapZ! {f} {
uplevel 1 set $f \[zapZ \[set $f\]\]
}
proc zapZ {f} {
global manx
return [expr {[regexp $manx(zregexp) $f]?[file rootname $f]:$f}]
}



proc manShowText {f0 {w .man} {keep 0}} {
global man manx stat

set wi $w.info


set t $w.show

if {[string match <* $f0]} {
set f [fileexp [string range $f0 1 end]]
if {[string length $f]==0} return
if {[regexp $manx(zregexp) $f]} {set f "|$man(zcat) $f"}
} else {set f [pipeexp $f0]}


manNewMode $w txt; incr stat(txt)

manTextOpen $w
if {[catch {
set fid [open $f]
$t insert end [read $fid]
close $fid
}]} {manTextClose $w; manWinstderr $w "Trouble reading $f0"; return}
manTextClose $w
if {!$keep} {pack forget $w.dups}

if {[file isfile $f]} {cd [file dirname [glob $f]]}



set manx(man$w) $f0
set manx(num$w) X
set manx(hv$w) [bolg [zapZ $f] ~]
set manx(manfull$w) $f0
set manx(catfull$w) $f
set manx(name$w) $f0
manShowManStatus $w

manWinstdout $w $manx(manfull$w)
manHighlights $w get; manYview $w
focus $t

return $f
}




proc manShowTexi {f0 {w .man} {keep 0}} {
global man manx stat

set t $w.show
set wi $w.info

set f $f0

manNewMode $w texi; incr stat(texi)

manTextOpen $w
texiShow $t $f $man(texinfodir)
manTextClose $w

if {!$keep} {pack forget $w.dups}




set manx(man$w) $f0
set manx(num$w) X
set manx(hv$w) [bolg [zapZ $f] ~]
set manx(manfull$w) $f0
set manx(catfull$w) $f
set manx(name$w) [file tail $f0]

manShowManFoundSetText $w $t $manx(hv$w)
manShowManStatus $w



manWinstdout $w $manx(manfull$w)
manHighlights $w get
if {[info exists manx(yview,$manx(hv$w))]} {
regexp {(.*)/(.*)} $manx(yview,$manx(hv$w)) all sect junk
texiFault $t js$sect
}
manYview $w

return $f
}




proc manShowRfc {f0 {w .man} {keep 0}} {
global rfcmap stat

manNewMode $w rfc; incr stat(rfc)

manShowText $f0 $w $keep
set t $w.show
set state [$t cget -state]
$t configure -state normal
while {[$t get 1.0] eq "\n"} {$t delete 1.0}
set index 1.0
while {[set index [$t search -forwards -regexp "^\f" $index end]]!=""} {
scan [$t index "$index linestart -1l"] "%d" back
while {[$t get $back.0] ne "\n"} {incr back -1}
while {[$t get $back.0] eq "\n"} {incr back -1}
incr back
scan [$t index "$index linestart +1l"] "%d" forward
while {[$t compare $forward.0 < end] && [$t get $forward.0] ne "\n"} {incr forward}
while {[$t compare $forward.0 < end] && [$t get $forward.0] eq "\n"} {incr forward}
incr forward -1
$t delete $back.0 "$forward.0 lineend"; # keep a \n separation (sometimes right, sometimes wrong)
}

if 0 {
set index 1.0
set js 1
while {[$t get $index]!=" "} {set index [$t index $index+1l]}
while {[set index [$t search -forwards -regexp {^[^ ]} $index+1l end]]!=""} {
$t mark set js$js $index; incr js
}
manShowManFoundSetText $w $t $f0
}
$t configure -state $state

return $f0
}



proc manApropos {name {w .man}} {
global man manx mani stat

if {$manx(shift)} { set manx(shift) 0; set w [manInstantiate] }
set wi $w.info; set t $w.show

if {$name eq ""} {set name $manx(man$w)}
if {$name eq ""} {
manWinstderr $w "Type in keywords to search for"
return
}

set form {}
lappend form " Apropos search for \"$name\"\n\n" {}
manWinstdout $w "Apropos search for \"$name\" ..." 1

DEBUG {puts "manApropos: exec $man(apropos) $name $man(aproposfilter) 2>/dev/null"}
if {[catch {set tmp [eval exec "$man(apropos) $name $man(aproposfilter) 2>/dev/null"]} info] || [string trim $tmp] eq ""} {
if {$info ne ""} {
lappend form $info i
} else {
lappend form "Nothing related found.\n" i
}
if {$man(glimpse)!=""} { lappend form "Try a full text search with Glimpse.\n" {}}
set mani(apropos,cnt) 0
} else {
manNewMode $w aprops; incr stat(apropos)
set mani(apropos,update) [clock seconds]
set cnt 0
foreach line [split $tmp "\n"] {
regsub "^\\.\[^ \t\]+" $line "" line
regsub -all "\[\t \]+" $line " " line
regsub " - " $line "\t - " line
regsub -all {[][{}"]} $line "" line
if {[lfirst $line] eq [lsecond $line]} { regsub {^[ ]*[^ ]+[ ]*} $line "" line }

if {[regexp "(\[^\t]+)\t+(.*)" $line all cmds desc]} {
} elseif {[regexp "(.+)  +(.*)" $line all cmds desc]} {
} else {set cmds [lindex $line 0]; set desc [lrange $line 1 end]}
lappend form $cmds manref "\t$desc\n" {}
incr cnt
}
.vols entryconfigure "apropos*" -state normal

set mani(apropos,cnt) $cnt
set manx(yview,apropos) 1/1.0
}
set mani(apropos,form) $form
set mani(apropos,shortvolname) "apropos"

manShowSection $w apropos
}




proc manHelp {w} {
global man manx stat tk_library

set t $w.show; set wi $w.info

manNewMode $w help; incr stat(help)
wm title $w "$manx(title$w) v$manx(version)"
set manx(manfull$w) "_help"
set manx(name$w) "_help"

manTextOpen $w
manHelpDump $t
$t tag remove h1 1.0 "1.0 lineend"; $t tag add title 1.0 "1.0 lineend"
$t delete 2.0
$t image create 2.0 -image icon -padx 8 -pady 8
$t mark set insert "author1+2lines lineend"
$t insert insert "\t"
$t image create insert -image face -align bottom -padx 8 -pady 8

set demo [file join $tk_library demos widget]
if {[file executable $demo]} {
button $t.demo -text "run Tcl/Tk demo" -foreground $man(textfg) -background $man(textbg) -font $man(textfont) \
-command "exec \[info nameofexecutable\] $demo &"
$t window create [list [$t search "Tcl/Tk" 1.0]  lineend] -window $t.demo -align bottom -padx 8
}

manManpathCheck
set fWarn 0
foreach warn {stray manpath mandesc} {
if {$manx($warn-warnings)!=""} {
$t insert 1.0 $manx($warn-warnings)\n\n
set fWarn 1
}
}
if {$fWarn} {$t insert 1.0 "Warnings\n\n" b}

$t insert 1.0 $manx(updateinfo)

manTextClose $w


set sectcnt 0; set subsectcnt 0
foreach i [lsort -command "bytextposn $t " [$t mark names]] {
if {[string match "*1" $i]} { $t mark set js[incr sectcnt] $i; set subsectcnt 0; $t mark unset $i }
if {[string match "*2" $i]} { $t mark set js$sectcnt.[incr subsectcnt] $i; $t mark unset $i }
}

manShowManFoundSetText $w $t "_help"
manShowTagDist $w h2
manHighlights $w get


update idletasks
after 1 "manWinstdout $w \"TkMan v$manx(version) of $manx(date)\""
}

proc bytextposn {t a b} {
return [expr {[$t compare $a < $b]?-1:[$t compare $a > $b]}]
}



proc manKeyNav {w m k} {
global man manx

set t $w.show; set wi $w.info
if {[catch {set isearch [$t index isearch.first]}]} {set isearch -1}

set firstmode [regexp "section|apropos" $manx(mode$w)]
set casesen [expr {$firstmode?1:$man(incr,case)}]

set fFound [searchboxKeyNav $m $k $casesen $t $wi $firstmode [expr {$manx(tryoutline$w)?"-elide":""}]]
if {[catch {set isearch2 [$t index isearch.first]}]} {set isearch2 -1}
if {$isearch2!=-1 && $isearch!=$isearch2} {manOutlineYview $t isearch.first}

return $fFound
}




proc manSave {} {
global man manx env

if {[file dirname $manx(startup)] eq "/"} return; # no save file for root
if {$manx(savegeom)} {set man(geom) [wm geometry .man]}
set w [manPreferencesMake]
if {[winfo exists $w]} {set man(geom-prefs) [geom2posn [wm geometry $w]]}

set nfn $manx(startup)
set ofn $manx(startup).bak

if {![file exists $nfn] || [file writable $nfn]} {
if {[file exists $nfn]} {file copy -force $nfn $ofn}
if {[catch {set fid [open $nfn w]}]} {
manWinstderr .man "$nfn is probably on a read-only filesystem"
return
}
foreach p [info procs *SaveConfig] {eval $p $fid}
puts $fid "manDot\n"
puts $fid $manx(userconfig)

if {[file exists $ofn]} {
set ofid [open $ofn]
set p 0
while {[gets $ofid line]!=-1} {
if {$p} {puts $fid $line} \
elseif {$manx(userconfig) eq $line} {set p 1}
}
close $ofid
}
close $fid
}

}




proc manSaveConfig {fid} {
global man manx high default tcl_platform tk_patchLevel


puts $fid "#\n# TkMan v$manx(version)"
puts $fid "# configuration saved on [clock format [clock seconds]]"
puts $fid "#"
puts $fid "# Tcl [info patchleve]/Tk $tk_patchLevel   [winfo interps]"
puts $fid "# $tcl_platform(os) $tcl_platform(osVersion) / $tcl_platform(machine), [winfo server .]"
puts $fid "# screen [winfo vrootwidth .]x[winfo vrootheight .], [winfo visual .] [winfo screendepth .] / [winfo visualsavailable .]"
puts $fid "#\n"

set preamble {
Elements of the man array control many aspects of operation.
Most, but not all, user-controllable parameters are available
in the Preferences panel.  All parameters are listed below.
Those that are identical to their default values are commented
out (preceded by \"#\") so that changes in the defaults will propagate nicely.
If you want to override the default, uncomment it and change the value
to its new, persistent setting.
}
foreach line [split [textmanip::linebreak $preamble] "\n"] {puts $fid "# $line"}
puts $fid ""



manStatsSet; # update its value
foreach i [lsort [array names man]] {
if {[info exists default($i)]} {
set co [expr {$default($i) eq $man($i)? "#" : ""}]
puts $fid "${co}set [list man($i)] [tr [list $man($i)] \n \n$co]"
} elseif {[string match "/*" $i]} {puts $fid "set man($i) $man($i)"}
}

puts $fid "\n\n#\n# Highlights\n#\n"
foreach i [lsort [array names high]] {
puts $fid "set [list high($i)] [list $high($i)]"
}

puts $fid "\n"
}




proc manStatsSaveFile {} {
global man manx

DEBUG {puts -nonewline "manStatsSaveFile"}
if {$manx(statsdirty) && [file readable $manx(startup)] && [file writable $manx(startup)]} {

set fid [open $manx(startup)]; set startup [read $fid]; close $fid

manStatsSet
foreach var {stats pagecnt} {
set stats "set man($var) [list $man($var)]\n"

if {[regsub "set man\\($var\\)\[^\}\]+\}\n" $startup $stats nstartup]} {
set startup $nstartup
DEBUG {puts -nonewline "\tfound existing variable"}
} elseif {[regsub "\n\n$manx(userconfig)\n" $startup "\n\n$stats\n$manx(userconfig)\n" nstartup]} {
set startup $nstartup
DEBUG {puts -nonewline "\tinserted before userconfig"}
} else {
append startup $stats
DEBUG {puts -nonewline "\tappended"}
}
}

set fid [open $manx(startup) "w"]; puts -nonewline $fid $startup; close $fid
DEBUG {puts -nonewline "\tsaved to file"}
}
DEBUG {puts ""}

after [expr 5*60*1000] manStatsSaveFile
}


set man(prof) {}
proc manStatsSet {} {
global man manx stat pagecnt short prof

DEBUG {puts "manStatsSet"}
trace vdelete stat w manStatsDirty
trace vdelete pagecnt w manStatsDirty
scan $man(stats) "%d" stat(cum-time)
set newstats $stat(cum-time)

set tmp {}
foreach p [array names prof cnt-*] {
set name [string range $p 4 end]
lappend tmp [list $name $prof(cnt-$name) $prof(totaltime-$name)]
}
set man(prof) ""
set cnt 0
foreach p [lsort -decreasing -real -index 2 $tmp] {
set name [lfirst $p]
append man(prof) "\n\t" $name " \"$prof(cnt-$name) $prof(totaltime-$name)\""
incr cnt
}
append man(prof) "\n"


foreach i $manx(all-stats) {
if {[set index [lsearch $man(stats) $i]]>=0} {
set stat(cum-$i) [lindex $man(stats) [expr {$index+1}]]
} else {
set stat(cum-$i) $stat($i)
}

incr stat(cum-$i) [expr {$stat($i)-$stat(cur-$i)}]
set stat(cur-$i) $stat($i)

lappend newstats $i $stat(cum-$i)
}
set man(stats) $newstats

set man(shortcuts) {}
foreach i $manx(shortcuts) {lappend man(shortcuts) [list $i $short($i)]}

set man(pagecnt) ""
set cnt 0
set tmp {}
foreach name [array names pagecnt] {lappend tmp [concat $name $pagecnt($name)]}; # want a destructive concat
foreach i [lsort -index 1 -integer -decreasing $tmp] {
set name [lfirst $i]
append man(pagecnt) [expr {$cnt%2==0? "\n\t": " "}] $name " \"$pagecnt($name)\""
incr cnt
}
append man(pagecnt) "\n"

set newchrono [lreplace $man(chronobrowse) end end "$manx(startuptime)/[expr {[clock seconds]-$manx(startuptime)}]/$manx(reading):$stat(man)/$stat(texi)/$stat(rfc)"]
set man(chronobrowse) "\n\t"
set cnt 0
foreach tuple $newchrono {
incr cnt
append man(chronobrowse) $tuple [expr {$cnt%4==0? "\n\t": " "}]
}
append man(chronobrowse) "\n"


trace variable stat w manStatsDirty
trace variable pagecnt w manStatsDirty
set manx(statsdirty) 0
}

proc manStatsDirty {name1 name2 op} {
global manx mani
DEBUG {puts "manStatsDirty: $name2"}
set manx(statsdirty) 1
}





proc manDot {} {
global manx

manManManx

foreach font {textpro gui guisymbol guimono peek textmono} {font create $font}
manPrefDefaultsSet

toplevel .man -class TkMan
manPreferencesGet fill

set manx(manDot) 1
}

proc manManManx {} {
global man manx
foreach i {
iconify iconname iconbitmap iconmask iconposition
geom 
} {
if {![info exists manx($i)]} {set manx($i) $man($i)}
}
}



proc manBinCheck {{inx 0} {err 0}} {
global man manx env stat


set var [lindex $manx(binvars) $inx]
set val [string trim [set $var]]
if {$val!=""} {
DEBUG {puts "manBinCheck on $var"}

foreach pipe [split $val "|"] {
set bin [lfirst $pipe]
if {$manx(doze)} {append bin ".exe"}
set found 0

if {[string match "/*" $bin]} {set pathlist [file dirname $bin]; set tail [file tail $bin]
} else {set pathlist $manx(bin-paths); set tail $bin}

foreach dir $pathlist {
if {$dir eq "."} continue
set fullpath $dir/$tail
if {[file isfile $fullpath] && [file executable $fullpath]} {
set found 1
set stat(bin-$bin) $fullpath
DEBUG { puts "$bin => $fullpath" }
break
}
}

if {!$found} {
puts stderr "$bin not found in your PATH--check the $var variable in $manx(startup) or the Makefile."
incr err
} else {
if {[set info [lassoc $manx(bin-versioned) $tail]]!=""} {
foreach {flag minvers} $info {}
set execerr [catch {set lines [exec $fullpath $flag < /dev/null 2> /dev/null]} info]
} elseif {[string match "g*" $tail]} {
set minvers 0.0
set execerr [catch {set lines [exec $fullpath $flag < /dev/null]} info]
set execerr 0; set lines $info
} else continue

if {$execerr && $minvers==0.0} {
} elseif {$execerr} {
puts "ERROR executing \"$fullpath $flag\": $info\a"
incr err
} else {
set line ""; foreach line [split $lines "\n"] { if {$line!=""} break }
set vers unknown
if {$line eq "" || ![regexp $manx(bin-versregexp) $line vers] || [package vcompare $minvers $vers]==1} {
if {$minvers!=0.0} {
puts stderr "$bin is version $vers--must be at least $minvers."
incr err
}
} else { set stat(bin-$bin-vers) $vers }
}
}
}
}

incr inx
if {$inx<[llength $manx(binvars)]} {
after 1000 manBinCheck $inx $err
} else {
if {$err} {exit 1}
.occ entryconfigure "Statistics*" -state normal
}

}

proc manParseCommandline {} {
global manx argv argv0 env geometry

for {set i 0} {$i<[llength $argv]} {incr i} {
set arg [lindex $argv $i]; set val [lindex $argv [expr {$i+1}]]
switch -glob -- $arg {
-help -
-h* -
--help {
set helptxt {
[-M <MANPATH>] [-M+ <paths to append to MANPATH>] [-+M <paths to prepend to MANPATH>]
[-[!]iconify] [-version]
[-title <string>] [-startup <file>] [-[!]debug] [<man page>[(<section>)]]
}
puts -nonewline "tkman"
foreach line [split [textmanip::linebreak $helptxt 70] "\n"] { puts "\t$line" }
exit 0
}
-M {set env(MANPATH) $val; incr i}
-M+ {append env(MANPATH) ":$val"; incr i}
-+M {set env(MANPATH) "$val:$env(MANPATH)"; incr i}
-dpi {set manx(dpi) $val; lappend manx(dpis) $val; incr i}
-profile {set manx(profile) 1}
-iconname {set manx(iconname) $val; incr i}
-iconmask {set manx(iconmask) $val; incr i}
-iconposition {set manx(iconposition) $val; incr i}
-iconbitmap {set manx(iconbitmap) $val; incr i}
-icon* {set manx(iconify) 1}
-noicon* {set manx(iconify) 0}
-quit {if {[string match no* $val]} {set manx(quit) 0}; incr i}
-start* {set manx(startup) $val; incr i}
-data* {puts stderr "-database option obsolete: database kept in memory"; incr i}
--v* -
-v* {puts stdout "TkMan v$manx(version) of $manx(date)"; exit 0}
-t* {set manx(title) $val; incr i}
-d* {set manx(debug) 1; set manx(quit) 0; set manx(iconify) 0}
-nod* {set manx(debug) 0}
-* {puts stdout "[file tail $argv0]: unrecognized option: $arg"; exit 1}
default {
after 2000 manShowMan $arg {{}} .man
break
}
}
}
if {[info exists geometry]} {set manx(geom) $geometry}
}


proc ASSERT {args} {
if {![uplevel 1 eval $args]} {
puts "ASSERTION VIOLATED: $args"
exit 1
}
}

proc DEBUG {args} {
global manx
if {$manx(debug)} {uplevel 1 eval $args}
}

set manx(lastclick) 0
proc PROFILE {msg} {
global manx
set clicknow [clock clicks]
if {$manx(profile)} {puts "$msg, delta=[expr {$clicknow-$manx(lastclick)}]"}
set manx(lastclick) $clicknow
}





if {[package vcompare [info tclversion] $manx(mintcl)]==-1 || [package vcompare $tk_version $manx(mintk)]==-1} {
puts -nonewline stderr "Tcl $manx(mintcl)/Tk $manx(mintk) minimum versions required.  "
puts stderr "You have Tcl [info tclversion]/Tk $tk_version"
exit 1
} elseif {int([info tclversion])-int($manx(mintcl))>=1 || int($tk_version)-int($manx(mintk))>=1} {
puts stderr "New major versions of Tcl and/or Tk may have introduced\nincompatibilies in TkMan.\nCheck the TkMan home site for a possible new version.\n"
}
set manx(doze) [string equal "windows" $tcl_platform(platform)]





set curwin [set w .man]


set man(manList) {1 2 3 4 5 6 7 8 9 l o n p D}
set man(manTitleList) {
"User Commands" "System Calls" Subroutines
Devices "File Formats"
Games "Miscellaneous" "System Administration" "*** check contrib/*_bindings ***"
Local Old New Public "*** check contrib/*_bindings ***"
}
set man(stats) [clock seconds]
set man(time-lastglimpse) -1
set manx(styles) {normal bold italics bold-italics}
set manx(pts) {8 9 10 12 14 18 24 36}
set manx(sizes) {tiny small medium large larger huge}
set man(gui-family) "Times"
set man(gui-style) "bold"
set man(gui-points) "small"
set man(text-family) "New Century Schoolbook"
set man(text-style) "normal"
set man(text-points) "small"
set man(vol-family) "Times"
set man(vol-style) "normal"
set man(vol-points) "small"
set man(diffd-style) "normal"
set man(diffc-style) "bold-italics"
set man(diffa-style) "italics"
set man(textfont) textpro

set manx(fontfamilies) [lsort [string tolower [font families]]]


set man(isearch) {-background gray}
set man(search) {-background orange}; # eye-catching but not overbearing on long stretches
set man(lastposn) {-background gray90}
set man(autokey) {-foreground red}
set man(synopsisargs) {-background green}
set man(spot) {-background red}
set man(manref) {sanserif -foreground blue}
set man(hot) {-foreground red}
set man(highlight) {-background #ffd8ffffb332}; # a pale yellow
set man(indent) {-lmargin1 5m -lmargin2 10m}
set man(indent2) {-lmargin1 10m -lmargin2 15m}


set manx(tags) {diffa diffd diffc title h1 h2 h3 tt t sc y b bi i highlight highlight-meta search autosearchtag autokey isearch manref hot indent indent2 spot synopsisargs lastposn
r asis example smallexample display table list subscript superscript lisp smalllisp code kbd key file var emph author strong dfn chapter section subsection subsubsection majorheading titlefont heading subheading subsubheading w deffn defun defmac defspec quotation index cite subtitle author flushleft flushright center cartouche nowrap texixref rfcxref
}
set man(diffa) {"$man(diffa-style)"}
set man(diffc) {"$man(diffc-style)"}
set man(diffd) {"$man(diffd-style)" -overstrike yes -foreground "$man(difffg)" s}
set man(strike) {-overstrike yes}
set man(tt) [set man(t) mono]
set man(sc) s
set man(y) symbol
set man(b) bold
set man(bi) bold-italics
set man(i) italics
set man(title) {bold large l}
set man(h1) {bold l}
set man(h2) {bold m}
set man(h3) {bold s}
set man(h4) {s}
set man(r) {}
set man(asis) {}
set man(example) {mono small s -wrap none -tabs 0.3i}
set man(lisp) {mono small -wrap none}
set man(smalllisp) {mono small s -wrap none}
set man(smallexample) $man(smalllisp)
set man(display) {-lmargin1 0.3i -lmargin2 0.3i -rmargin 0.3i}
set man(table) {-tabs 1.0i -lmargin2 1.0i}
set man(list) {-tabs 0.3i -lmargin2 0.3i}
set man(subscript) {-offset -3}
set man(superscript) {-offset 3}
set man(code) {mono small}
set man(kbd) {mono}; set man(key) $man(sc)
set man(url) {mono}
set man(file) {italics}
set man(var) {italics}
set man(emph) {italics}
set man(strong) {bold}
set man(deffn) {italics}
set man(defun) {italics}
set man(defmac) {italics}
set man(defspec) {italics}
set man(author) {bold}
set man(dfn) {bold}
set man(chapter) [set man(majorheading) [set man(titlefont) {bold m}]]
set man(section) [set man(heading) {bold s}]
set man(subsection) [set man(subheading) {italics}]
set man(subsubsection) [set man(subsubheading) {}]
set man(cite) {italics}
set man(cartouche) {-borderwidth 2}
set man(subtitle) {italics}
set man(author) {bold}
set man(center) {center}
set man(flushleft) {left}
set man(flushright) {right}
set man(w) {}
set man(nowrap) {-wrap none}
set man(quotation) {-lmargin1 0.5i -lmargin2 0.5i -rmargin 0.5i}
set man(index) {s -tabs 3i}
set man(texixref) $man(manref)
set man(rfcxref) $man(manref)
set man(maxhistory) 15; set manx(maxhistory-v) [set manx(maxhistory-t) {5 10 15 20 30 40 50}]
set man(recentdays) 14; set manx(recentdays-v) [set manx(recentdays-t) {1 2 7 14 30 60 90 180}]
set man(pagecnt) {}
set man(chronobrowse) {}
set man(shortcuts) {}
set man(shortcuts-sort) 0; set manx(shortcuts-sort-v) {1 0}; set manx(shortcuts-sort-t) {"alphabetical" "chronological"}
set manx(indexglimpse-v) [set manx(indexglimpse-t) {"distributed" "unified"}]
set man(incr,case) -1; set manx(incr,case-v) {1 0 -1}; set manx(incr,case-t) {"yes" "no" "iff upper"}
set man(regexp,case) -1; set manx(regexp,case-v) {1 0 -1}; set manx(regexp,case-t) {"yes" "no" "iff upper"}
set man(maxglimpse) 200; set manx(maxglimpse-v) [set manx(maxglimpse-t) {25 50 100 200 500 1000 "none"}]
set man(maxglimpseexcerpt) 50; set manx(maxglimpseexcerpt-v) [set manx(maxglimpseexcerpt-t) {25 50 100 200 500 1000}]
set man(autoraise) 0; set manx(autoraise-v) {1 0}; set manx(autoraise-t) {"yes" "no"}
set man(autolower) 0; set manx(autolower-v) {1 0}; set manx(autolower-t) {"yes" "no"}
set man(iconify) 0; set manx(iconify-v) {1 0}; set manx(iconify-t) {"yes" "no"}
set man(focus) 1; set manx(focus-v) {1 0}; set manx(focus-t) {"window entry" "click-to-type"}
set man(subsect) ""; set manx(subsect-v) {"-b" ""}; set manx(subsect-t) {"yes" "no"}
set man(nroffsave) "off"; set manx(nroffsave-v) [set manx(nroffsave-t) {"on" "on & compress" "off" "off & ignore cache"}]
set man(headfoot) "-k"; set manx(headfoot-v) {"-k" ""}; set manx(headfoot-t) {"yes" "no"}
set man(hyperclick) "single"; set manx(hyperclick-v) [set manx(hyperclick-t) {"double" "single"}]
set man(fsstnddir) /var/catman
set man(fsstnd-always) 0; set manx(fsstnd-always-v) {1 0}; set manx(fsstnd-always-t) {"always" "iff .../canN unwritable"}
set man(versions) {}
set man(aproposfilter) {| sort | uniq}
set man(scrollbarside) right; set manx(scrollbarside-v) [set manx(scrollbarside-t) {"left" "right"}]
set man(documentmap) 1; set manx(documentmap-v) {1 0}; set manx(documentmap-t) {"yes" "no"}
set man(strictmotif) 0; set manx(strictmotif-v) {1 0}; set manx(strictmotif-t) {"yes" "no"}
set man(subvols) 1; set manx(subvols-v) {1 0}; set manx(subvols-t) {"yes" "no"}
set man(preferGNU) ""; set manx(preferGNU-v) {"g?" ""}; set manx(preferGNU-t) {"yes" "no"}
set man(preferTexinfo) 1; set manx(preferTexinfo-v) {1 0}; set manx(preferTexinfo-t) {"yes" "no"}
set man(wordfreq) 0; set manx(wordfreq-v) {1 0}; set manx(wordfreq-t) {"yes" "no"}
set man(search,fcontext) 0; set manx(search,fcontext-v) [set manx(search,fcontext-t) {0 1 2 3 4 5}]
set man(search,bcontext) 0; set manx(search,bcontext-v) [set manx(search,bcontext-t) {0 1 2 3 4 5}]
set man(textboxmargin) 5; set manx(textboxmargin-v) [set manx(textboxmargin-t) {0 1 2 3 4 5 7 10}]
set man(lengthchunk) "line"; set manx(lengthchunk-v) {line screen page ""}; set manx(lengthchunk-t) {"lines" "screenfuls" "printed pages" "no report"}; # "line/screen"
set manx(line-scale) 1; set manx(screen-scale) 45; set manx(page-scale) [expr int(60*1.5)]
set man(error-effect) "bell & flash"; set manx(error-effect-v) [set manx(error-effect-t) {"bell & flash" "bell" "flash" "none"}]
set man(columns) 65; set manx(columns-v) {65 90 130 5000}; set manx(columns-t) {"65 (most compatible)" 90 130 "wrap to screen width"}; # no one would want shorter lines
set manx(longtmp) /tmp/ll
set man(volcol) 4.0c; set manx(volcol-v) {0 1.5c 2.0c 2.5c 3.0c 3.5c 4.0c 4.5c 5.0c 7.5c 10.0c}; set manx(volcol-t) {"no columns" "1.5 cm" "2 cm" "2.5 cm/~1 inch" "3 cm" "3.5 cm" "4 cm" "4.5 cm" "5.0 cm/~2 inches" "7.5 cm" "10 cm"}
set man(apropostab) "4.5c"; set manx(apropostab-v) {0 3.0c 4.0c 4.5c 5.0c 5.5c 6.0c 7.5c 10.0c}; set manx(apropostab-t) {"none" "3 cm" "4 cm" "4.5 cm" "5 cm" "5.5 cm" "6 cm" "7.5 cm" "10 cm"}
set man(high,hcontext) 50
set man(high,vcontext) 5; set manx(high,vcontext-v) [set manx(high,vcontext-t) {0 2 5 7 10 15 20}]
set man(outline) "allbut"; set manx(outline-v) {"allexp" "allcol" "allbut" "off"}; set manx(outline-t) {"all expanded" "all collapsed" "all collapsed but" "none"}
set man(outlinebut) {^name\d+$|(syntax|synopsis)[1-2]?\d$|description\d$|(author|identification|credits)\D*[1-9]$|(see also|related information)\d$}
set man(autosearchnb) {unsafe|warning|danger|obsolete|international|english|posix|web|performance|privacy|security|authoritative|deadlock|berkeley|solaris|version \d+}
set man(autosearch) {fail|ignore|explicit|difficult|tricky|postscript|html|priority|wait|block}
set man(autokeywords) {default|return|null|empty|inclusive|exclusive|sensitive|insensitive|ascii|octal|hex|dec |decimal|symbolic}; # not dec=>december
foreach i {highlight options search manfill manref} {
set manx($i-show-v) {"alwaysvis" "firstvis" "never"}
set manx($i-show-t) {"always" "at first" "never"}
}
set manx(openFilePWD) [pwd]
set manx(pathsep) [expr {$manx(doze)?";": ":"}]; # Tcl seems not to have addressed this
set man(randomscope) all
set manx(manhits) {}
set man(tidyout) 1; set manx(tidyout-v) {1 0}; set manx(tidyout-t) {"yes" "no"}
set manx(highlight-show-v) {"halwaysvis" "firstvis" "never"}
set manx(search-show-v) {"salwaysvis" "sfirstvis" "never"}; # is "never" never a good choice?
set manx(manfill-show-v) {"malwaysvis" "mfirstvis" "never"}
set manx(show-atags) {alwaysvis halwaysvis salwaysvis malwaysvis}
set manx(show-ftags) {firstvis mfirstvis sfirstvis lastposn}
set manx(show-tags) [concat lastposn $manx(show-atags) $manx(show-ftags)]
set man(highlight-show) halwaysvis; #firstvis
set man(options-show) firstvis
set man(manref-show) never
set man(search-show) salwaysvis
set man(manfill-show) mfirstvis
set man(manfill-sects) {description introduction command usage operators}
set man(manfill) "in entirety"; set manx(manfill-v) [set manx(manfill-t) {"in entirety" "as space"}]
set man(showsectmenu) 1; set manx(showsectmenu-v) {1 0}; set manx(showsectmenu-t) {"yes" "no"}
set man(rebus) 0; set manx(rebus-v) {1 0}; set manx(rebus-t) {"yes" "no"}
set man(tryfuzzy) 1; set manx(tryfuzzy-v) {1 0}; set manx(tryfuzzy-t) {"yes" "no"}
set man(showrandom) 0; set manx(showrandom-v) {1 0}; set manx(showrandom-t) {"yes" "no"}
set man(maxpage) 0; set manx(maxpage-v) {1 0}; set manx(maxpage-t) {"yes" "no"}
set man(geom) [min 570 [expr {[winfo screenwidth .]-100}]]x[min 800 [expr {[winfo screenheight .]-50}]]+100+10
set man(geom-prefs) +300+300
set man(iconname) {TkMan: $manx(name$curwin)}
set man(iconbitmap) "(default)"
set man(iconmask) ""
set man(iconposition) ""
set man(startup) $env(HOME)/.tkman

set man(colors) {black white red "light yellow" yellow orange green blue beige SlateGray4 gray75 gray90}

set man(textfg) "black"
set man(textbg) "white"
set man(difffg) "gray60"

checkbutton .a
set man(buttfg) [set man(guifg)  [.a cget -foreground]]
set man(guibg) [set man(buttbg) [.a cget -background]]
set man(activefg) [.a cget -activeforeground]
set man(activebg) [.a cget -activebackground]
destroy .a
set man(selectionfg) black
set man(selectionbg) gray90

set manx(dpi) [expr {int([winfo screenwidth .]/([winfo screenmmwidth .]/25.4))}]
if {[catch {set bestdpi $env(DISPLAY_DPI)}]} {
set bestdpi 75; set mindpidiff 1000
foreach dpi $manx(dpis) {
set dpidiff [expr {abs($dpi-$manx(dpi))}]
if {$dpidiff<$mindpidiff} {set mindipdiff $dpidiff; set bestdpi $dpi}
}
}
tk scaling [expr {$bestdpi/72.0}]


set manx(mono) [expr {[winfo depth .]==1}]
if {$manx(mono)} {
set man(foreground) "black"
set man(background) "white"
set man(colors) {black white}
set man(activebg) [set man(buttfg) [set man(guifg) "black"]]
set man(difffg) [set man(activefg) [set man(buttbg) [set man(guibg) "white"]]]
set man(selectionfg) $man(textbg); set man(selectionbg) $man(textfg); # gotta reverse on b&w

set man(search) [set man(isearch) "reverse"]
set man(highlight) "bold-italics"
set man(manref) "mono underline"
set man(spot) reverse

}
set man(highlight-meta) $man(highlight)


set man(print) [string trim $man(print)]
foreach i [array names man] {set default($i) $man($i)}



set manx(title) "TkMan"
regexp {(\d\d\d\d)/(\d\d)/(\d\d)} {$Date: 2003/04/01 23:02:52 $} manx(date) y m d
set manx(mtime) [clock scan "$m/$d/$y"]
set manx(stray-warnings) ""
if {[catch {set default(manList) 0}]} {puts "\aBLT conflicts with TkMan."; exit 1}
set manx(manList) $man(manList)
set manx(manTitleList) $man(manTitleList)
set manx(userconfig) "### your additions go below"
set manx(posnregexp) {([-+]?\d+)([-+]\d+)}
set manx(bkupregexp) {(~|\.bak|\.old)}; # exclude old?  may want to refer to it => make it an option?
set manx(init) 0
set manx(texishowsubs) ""
set manx(manDot) 0
set manx(cursor) left_ptr
set manx(yview,help) 1/1.0
set manx(paths) ""
set manx(pathstat) ""
set manx(uid) 1
set manx(hunkid) ""
set manx(outcnt) 1
set manx(debug) 0
set manx(profile) 0
set manx(defaults) 0
set manx(startup) $man(startup)
set manx(savegeom) 1
set manx(lastman) TkMan
set manx(censussortby) 1
set manx(highsortby) 0
set manx(normalize) "-N"
set manx(quit) 1
set manx(mandot) ""
set manx(db-manpath) ""
set manx(db-signature) ""
set manx(mondostats) 0
set manx(newmen) ""
set manx(highdontask) {}
set manx(subdirs) "{sman,man,cat}?*"
set manx(shift) 0
set manx(searchtime) 0
if {[file executable /usr/ucb/whoami]} {set manx(USER) [exec /usr/ucb/whoami]
} elseif {[file executable /usr/bin/whoami]} {set manx(USER) [exec /usr/bin/whoami]
} elseif {[info exists manx(USER)]} {set manx(USER) $env(USER)
} else {set manx(USER) "luser"}
append man(autosearchnb) "|$manx(USER)"; # vanity
if {[info exists env(PRINTER)]} {set manx(printer) $env(PRINTER)} \
elseif {[info exists env(LPDEST)]} {set manx(printer) $env(LPDEST)} \
else {set manx(printer) ""}

set manx(bin-versregexp) {(\d+\.\d+(\.\d+)*)}; # followed by ([^,;:\s]*)
set manx(bin-versioned) {{rman "-v" 3.1}}
set manx(modes) {man texi rfc help section txt apropos glimpse info}
set manx(mode-desc) {"manual pages seen" "Texinfo files read" "RFC documents read" "references to help page" "volume listings invoked" "text files seen" "apropos listings" "Glimpse full-text searches" "ganders at this page"}
DEBUG { assert [llength $manx(modes)]!=[llength $manx(mode-desc)] "mismatched modes lists" 1 }
set manx(stats) {man-hyper man-dups man-button man-history man-shortcut man-random page-section page-highlight-go page-highlight-add page-highlight-sub page-shortcut-add page-shortcut-sub page-regexp-next page-regexp-prev page-incr-next page-incr-prev page-downsmart page-mono high-exact high-move high-lose high-carry print glimpse-builds outline-expand outline-collapse instantiation checkpoint}
set manx(stats-desc) {"via hyperlink" "via multiple matches pulldown" "via man button or typein box" "via history menu" "via shortcut menu" "via random page" "jumps to section header" "jump to highlight" "highlight additions" "highlight deletions" "shortcut additions" "shortcut deletions" "regular expression searches forward" "regular expression searches backward" "incremental searches forward" "incremental searches backward" "scrolls with smart outline expansion/collapse" "swaps between proportional font and monospaced" "exact" "repositioned" "lost" "pages printed" "Glimpse builds" "expanded outline" "collapsed outline" "additional instantiations" "checkpoints to save file"}
DEBUG { assert [llength $manx(stats)]!=[llength $manx(stats-desc)] "mismatched stats lists" 1 }
set stat(man-no) 0
set manx(all-stats) [concat $manx(modes) $manx(stats) "man-no" "executions"]
foreach i $manx(all-stats) {set stat(cur-$i) [set stat($i) 0]}
set manx(zdirsect) {(?:man|sman|cat)\.?(.*)}



if {[info exists env(TKMAN)]} {set argv "$env(TKMAN) $argv"}
if {![info exists env(PATH)] || $env(PATH) eq ""} { set env(PATH) "/usr/local/bin:/usr/bin" }
set manx(bin-paths) [split [string trim $env(PATH) $manx(pathsep)] $manx(pathsep)]

manParseCommandline
set manx(startup-short) [file tail $manx(startup)]

if {![file exists $manx(startup)]} {eval $manx(newuser)}

set manx(savefilevers) "1.0"
set manx(updateinfo) ""


if {$manx(startup) ne "" && ![file exists $manx(startup)] && [file writable [file dirname $manx(startup)]]} {
catch {
set os [string tolower $tcl_platform(os)]; set osvers $tcl_platform(osVersion)
set setup ""; # most OSes work without configuration file

if {$os eq "sunos" && $osvers>=5.0} {
set setup solaris
if {$osvers>=5.7} {append setup "28"
} elseif {$osvers>=5.6} {append setup "26"
} elseif {$osvers>=5.5} {append setup "25"}
} elseif {[string match "irix*" $os]} {
set setup irix
} elseif {$os eq "sco_sv"} {
set setup $os
}

if {$setup!="" && [info exists manx($setup-bindings)]} {
set fid [open $manx(startup) "w"]
puts $fid $manx($setup-bindings)
close $fid
}
}
}



if {$manx(startup)!="" && [file readable $manx(startup)]} {
set fid [open $manx(startup)]

if {[string match "#!*" [gets $fid line]]} {
puts stderr "$manx(startup) looks like an executable."
puts stderr "You should delete it, probably."
exit 1
}

while {![eof $fid]} {
if {[regexp {^# TkMan v(\d+(\.\d+)+)} $line all savefilevers]} {
set manx(savefilevers) $savefilevers
break
}
gets $fid line
}
catch {close $fid}
DEBUG {puts "*** savefilevers = $manx(savefilevers)"}

source $manx(startup)



set fixup 0
if {[package vcompare $manx(savefilevers) 1.6]==-1} {
set manx(updateinfo) "Startup file information updated from version $manx(savefilevers) to version $manx(version).\n"

foreach var {catsig compress zcat} {
set man($var) $default($var)
}

foreach k {greater less question} {
set var "sb(key,MS-$k)"
if {[info exists $var]} {unset $var}
}

append manx(updatedinfo) "    Added call to manDot\n"


append manx(updateinfo) "Save updates via the Quit button or Occasionals/Checkpoint, or cancel updates via \"Occasionals / Quit, don't update\".\n"
if {![catch "file copy -force $manx(startup) [set ofn $manx(startup)-$manx(savefilevers)]"]} {
append manx(updateinfo) "Old startup file saved as $ofn\n"
}
append manx(updateinfo) "\n\n"
set fixup 1

}

if {[package vcompare $manx(savefilevers) 1.8.1]==-1} {
if {[info exists man(stats)] && [llength [lsecond $man(stats)]]==2} {
set newstyle [lfirst $man(stats)]
foreach s [lrange $man(stats) 1 end] { lappend newstyle [lfirst $s] [lsecond $s] }
set man(stats) $newstyle

set man(glimpse) $default(glimpse)
set man(glimpseindex) $default(glimpseindex)
set man(format) $default(format)

set fixup 1
}
}

if {[package vcompare $manx(savefilevers) 2.0]==-1} {
foreach db [glob -nocomplain ~/.tkmandatabase*] {file delete -force -- $db}
}

if {[package vcompare $manx(savefilevers) 2.1]==-1} {
set man(high,vcontext) 5
set man(autosearch) $default(autosearch); # autosearchnb and autokeywords are new in 2.1
}

if {[llength [lfirst $man(shortcuts)]]==1} {
set tmp {}
foreach i $man(shortcuts) {lappend tmp [list $i [clock seconds]]}
set man(shortcuts) $tmp
}
if {[info exists man(pagecnt)] && [llength [lsecond $man(pagecnt)]]==1} {
set tmp {}
foreach {name cnt lastread} $man(pagecnt) {lappend tmp $name [list $cnt $lastread]}
set man(pagecnt) $tmp
}
array set pagecnt $man(pagecnt)

if {!$manx(manDot)} {
manDot
set fixup 1
}

if {$fixup} {after 500 manSave}
} else {
}


if {$man(glimpse) eq "" || $man(glimpseindex) eq ""} {set man(glimpse) ""; set man(glimpseindex) ""}

if {[lindex $man(versions) end]!=$manx(version)} {lappend man(versions) $manx(version)}

set manx(shortcuts) {}
foreach i $man(shortcuts) {
foreach {name time} $i {lappend manx(shortcuts) $name; set short($name) $time}
}

catch {unset high(*)}


foreach {name info} $man(prof) {
set prof(cnt-$name) [lfirst $info]; set prof(totaltime-$name) [lsecond $info]
}


set manx(highs) [concat $manx(styles) reverse underline mono $man(colors)]

set manx(extravols) {}
if {$man(apropos) ne ""} {
lappend manx(extravols) [list apropos "apropos hit list" [list "No apropos list" b]]
}
if {$man(glimpse) ne ""} {
lappend manx(extravols) [list glimpse "glimpse hit list" [list "No glimpse list" b]]
if {$man(indexglimpse)=="unified" && [file readable [file join $man(glimpsestrays) ".glimpse_index"]]} {
lappend manx(extravols) [list "glimpseindex" "glimpse word index" {}]
}
}
lappend manx(extravols) {recent "Recently added/changed" {}} {high "All with Highlights" {}} {census "All pages seen" {}} {all "All Enabled Volumes" {}}
foreach i $manx(extravols) { lappend manx(specialvols) [lfirst $i] }

set manx(subregexp) {js(\.?(\d+))+}
set manx(supregexp) {js(\d+(\.\d+)*)\.\d+}
set manx(zregexp) "\\.("; set manx(zregexpopt) "(\\.("
set manx(zglob) "{"; set manx(zoptglob) "{,"
foreach z $man(zlist) {
append manx(zregexp) "$z|"
append manx(zregexpopt) "$z|"
append manx(zglob) "$z,"
append manx(zoptglob) ".$z,"
}
foreach z {zregexp zglob zoptglob} { set manx($z) [string trimright $manx($z) ",|"] }
set manx(zregexp0) "[string trimright $manx(zregexp) |])"
set manx(zregexpl) "(\\.\[^\\. \]+)$manx(zregexp0) "
set manx(zregexp) "$manx(zregexp0)\$"
set manx(zregexpopt) "[string trimright $manx(zregexpopt) |]))?"
append manx(zglob) "}"; append manx(zoptglob) "}"
set manx(filetypes) [list [list "Manual Pages" ".{\\\[1-9olnpD],man}*$manx(zoptglob)"] [list "Texinfo" ".texi$manx(zoptglob) .texinfo$manx(zoptglob)"] [list "Text file" ".txt$manx(zoptglob)"] {"Any file" *}]


set mani(MASTER,dirs) {}
foreach i $manx(mastermen) {
if {![file readable $i] || [lsearch $manx(paths) $i]!=-1} continue
foreach j [glob -nocomplain $i/man*] {
if {[file readable $j] && [file isdirectory $j]} {lappend mani(MASTER,dirs) $j}
}
}
set manx(aux-binpaths) {}
foreach i $manx(masterbin) {
if {[lsearch $manx(bin-paths) $i]==-1 && [file readable $i] && [file isdirectory $i]} {
lappend manx(aux-binpaths)
}
}




set manx(binvars) {
manx(rman) man(glimpse) man(glimpseindex) man(cksum) man(gzgrep)
man(format) man(print) man(catprint) man(apropos) man(zcat) man(compress) 
}

set manx(canformat) [expr {$man(format) ne ""}]
if {$manx(doze)} {
foreach var {format glimpse glimpseindex print catprint apropos} {
set man($var) ""
}

foreach var {MANPATH PATH} {
if {[info exists env($var)] && [string match "*//*" $env($var)]} {
set newvar $env($var)
regsub -all ":" $newvar "\;" newvar
regsub -all {//([A-Z])/} $newvar {\1:/} newvar
set env($var) $newvar
}
}
}

after 1500 manBinCheck


if {[llength $man(manList)]!=[llength $man(manTitleList)]} {
puts stderr "Length of section abbreviations differs from length of section titles:\n\nlength [llength $man(manList)]:\t$man(manList)\n\nlength [llength $man(manTitleList)]:\t$man(manTitleList)"
exit 1
}

set manx(glimpseindex) ""
if {$man(glimpse)!="" && $man(glimpseindex)!=""} {
foreach p $manx(paths) {
if {![file writable $p]} {set manx(glimpseindex) $man(glimpseindex); break}
}
}


if {!$manx(defaults)} manDescDefaults

lappend man(chronobrowse) "X"
set manx(statsdirty) 0
manStatsSet
if {[package vcompare $manx(savefilevers) 2.0.3]==-1} {set stat(cum-executions) $stat(cum-help); set man(stats) "executions $stat(cum-executions) $man(stats)"}
manStatsSaveFile;	# should just set timer this time through, not save to a file



if 0 {
foreach proc [info procs man*] {
puts -nonewline "rewriting $proc"
set vals ""; foreach aargh [info args $proc] {append vals " \$$aargh"}
set aarghs {}
foreach aargh [info args $proc] { if {[info default $proc $aargh def]} {lappend aarghs [list $aargh $def]} else {lappend aarghs $aargh}}
puts "   $aarghs"
proc $proc $aarghs "puts \"entering $proc $vals\"; flush stdout\n[info body $proc]\nputs {exiting $proc}; flush stdout"
}
}

set STOP 0


TkMan

set starttime [time manInit]
manHelp $w; # show newly available stray cat warnings


set t $w.show

entry $w.in -relief sunken -textvariable manx(debugcmd)
bind $w.in <KeyPress-Return> {manWinstdout .man "[eval $manx(debugcmd)]"}
bind $w.in <Meta-KeyPress-Return> {manTextOpen .man; $t insert end $manx(debugcmd) b "   =>   " tt "\n\n" {} [eval $manx(debugcmd)]; manTextClose .man}

DEBUG {
puts stdout "init takes $starttime"
pack $w.in -fill x
proc manStatsSaveFile args {}
}


set stat(executions) 1


if {$stat(cum-executions)==100 
|| ($stat(cum-executions)>0 && int($stat(cum-executions)/1000)*1000==$stat(cum-executions))} {
set txt "This is the $stat(cum-executions)th time you've run TkMan.  Please help improve future versions of TkMan by emailing the file ~/.tkman with its collected statistics to phelps@ACM.org.  (This must be done manually; no action is taken automatically.)  Thanks!"
manTextPlug $w.show 1.0 "$txt\n\n" b
tk_messageBox -icon info -parent $w -title "Please Help" -type ok -message $txt
}

if {$stat(cum-executions)%27==0} {
set txt ""
if {$man(texinfodir)==""} {append txt "+ In addition to showing manual pages, TkMan supports Texinfo (GNU documentation) with high quality text display, intra-document and full text search, highlight annotations, and an outlining interface that preserves navigation context to combat (solve?) the \"lost in info-space\" problem.  (To install, see the Makefile.)\n"}
if {$man(glimpse) eq ""} {append txt "+ You can do full text search on all man pages, Texinfo, and other text files by installing Glimpse.  (It's is conviently available as binaries.  To install, see the Makefile.)\n"}
if {$man(outline) eq "off"} {append txt "+ Now that you're comfortable with TkMan, try the outlining display (set Preferences/Outline/Outlining state at page load, to all collapsed but).  Rather than scolling screen after screen in a man page to find the information, outlining and Notemarks give a high density display that's likely to show the information you want on the first or second screenful.\n"}
if {$stat(cum-executions)>10 && $stat(cum-page-highlight-add)<10} {append txt "+ You can make yellow highlighter annotations.  If the page content changes or the page moves, highlights are automatically repositioned.\n"}
if {$stat(cum-executions)>10 && $man(outline)!="off" && $stat(cum-page-downsmart)<$stat(cum-man)/2} {append txt "+ Try using <Return> for smart scrolling through outlines, opening up closed sections as they are encountered and closing up sections as they are read.\n"}
if {!$man(wordfreq)} {append txt "+ You can get a kind of summary of man pages via word frequency counts (turn on at Preferences/See/Page summary).\n"}
if {$man(columns)!=5000} {
append txt "+ You can man page lines to wrap at whatever your screen width is (set Preferences/Database/Width of man pages)."
if {![string match "*groff*" $man(format)]} {append txt "  (But first you need to use groff, set in the Makefile or your ~/.tkman file)."}
append txt "\n"
}
if {$txt!=""} {
tk_messageBox -icon info -parent $w -title "Presents for you" -type ok -message "TkMan:  There are a couple great features you're not taking advantage of.  Click OK to read more."
manTextPlug $w.show 1.0 "$txt\n\n" b
wm deiconify $w
}
}
