Xref: news-dnh.mv.net comp.os.msdos.djgpp:443 Path: news-dnh.mv.net!mv!news.sprintlink.net!cs.utexas.edu!convex!not-for-mail From: rosenkra AT convex DOT com (William Rosenkranz) Newsgroups: comp.os.msdos.djgpp Subject: man(1) system (part01/01) Date: 19 Jun 1995 00:11:31 -0500 Organization: Engineering, Convex Computer Corporation, Richardson, Tx USA Lines: 2659 Nntp-Posting-Host: convex1.convex.com Summary: unix man, apropos, whatis Keywords: unix manual man whatis apropos To: djgpp AT sun DOT soe DOT clarkson DOT edu Dj-Gateway: from newsgroup comp.os.msdos.djgpp man (part01/01) this is a man(1) system. it has been run successfully under both unix and with gcc on the atari ST. untested under dos and djgpp, but it should port trivially. someone had asked for this, and i had it laying around. written circa 1991-1992. i am also posting whatis(1) (in 2 parts) that goes along with this. see the readme files for instructions. -bill rosenkranz rosenkra AT convex DOT com -------------------------- cut here -------------------------- # This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # # Wrapped by William Rosenkranz on Mon Jun 19 00:31:44 1995 # # This archive contains: # man # # Error checking via sum(1) will be performed. LANG=""; export LANG PATH=/bin:/usr/bin:$PATH; export PATH if sum -r /dev/null 2>&1 then sumopt='-r' else sumopt='' fi echo mkdir - man mkdir man echo x - man/README cat >man/README <<'@EOF' man v3.0.2 92/10/11 ------------------- This is a man(1) program, to be used in conjunction with manpager (which I concurrently posted). It is fairly robust, patterned after BSD unix man. It requires ul(1) and cat(1), if the "-" and "-ul" options are used, whatis(1) if the "-f" option is used, apropos(1) for the "-k" option, and always needs either less (setenv PAGER c:\bin\less.ttp) or manpager (setenv MANPAGER c:\bin\manpager.ttp). One of these is required, or you can setenv PAGER to your own prefered pager. Personally, I think less is superior over pg or more. And this version is really oriented toward using manpager, for reading nroff v1.10p4 manpages (with font changes). NOTE: the manpage posted here, "man.1", uses special escape sequences for changing fonts, so it must be viewed with manpager to get the full effect. You can also use less or emacs, in a pinch. What is nice about this man, is that it can deal with files compressed with compress(1), using the "-z" switch in manpager (less does not support this directly) without resorting to something like "zcat file | less". I tested man and manpager with the compress on atari.archive.umich.edu (terminator) which is v4.3, 16-bit. For more on this, see manpager docs. Incidently, when I say "man(1)", the "(1)" refers to the section of the unix programmer's manual (more on this below). Section 1 is user commands. It is just the way things are refered to in unix-land. I was going to post apropos(1), whatis(1), and whatisin(1), but they need more work before I do. No timeframe for this. Sorry. Anyway, it is pretty simple to use. To set up a manpage directory, do this: 1) mkdir c:\man (this is the root of the manpage tree, the default in the program, too, but you can use anything you like). 2) cd c:\man mkdir man0 man1 man2 man3 man4 man5 man6 man7 man8 mkdir manl mano mann. You will place formatted manpages in this tree (those already run through nroff). Normally, these would be called "catpages" and placed in .\cat*. man does NOT invoke nroff! 3) copy man.ttp to your bin directory and rehash your shell. man can also be run from the desktop, but you need an environment if you want to override the default man directory. 4) setenv MANDIR c:\man (or whatever). 5) setenv MANPAGER c:\bin\manpager.ttp. 6) put some manpages in the c:\man\man* directories as follows (note that file extensions ARE important and MUST correspond to the last char of the subdirectory): subdir filename description man0 *.0 general information man1 *.1 commands man2 *.2? system calls, my convention is *.2 normal unix system calls *.2g gemdos *.2b bios *.2x xbios man3 *.3? libraries, normal unix convention is *.3 general libc *.3s stdio (fopen, etc) *.3m math (sin, etc) *.3c compatibility *.3x others man4 *.4 devices, special files (for dev drivers on unix, i use it for things like sound.4, dma.4, etc) man5 *.5 file formats (e.g. arc.5, ar.5, tar.5) man6 *.6 games man7 *.7 misc man8 *.8 system administration (e.g. ramdisk.8) manl *.l local commands specific to your setup mano *.o old manpages (replaced with newer) mann *.n new manpages (for testing prior to install) You can start with man's manpage (cp man.1 c:\man\man1). 7) run man (man man) if you copied man.1 to c:\man\man1. You do not specify the section in the file name. note that if you have 2 manpages called "xyz" (i.e. xyz.1 and xyz.2), man will ALWAYS find xyz.1 and never the other. if you want xyz.2, you should specify the section as in "man 2 xyz". 8) if you want to use the -k and -f options, you will have to build a whatis(1) database, which is simply the NAME text from manpages, one per single line. the whatis entry for man is: man - read online documentation "whatis" is a file which goes in c:\lib. a sample is included here. Each time you add a manpage to the system, add the NAME line to whatis in the format specified (see whatis file). my own file has about 600 entries! You don't have to stick with these (BSD) conventions, but it will make life simpler. At any rate, the program requires the directory stucture and searches there. See the manpage (or source) for the search order. Try to put only unix commands in man1 (putting other commands like uniterm) in manl. I have hundreds of files in man1, and it gets to be a pain after a while. Note that it is not necessarily to have a manpage for 2 commands or functions which share the same manpage. You can "source" a manpage from another by placing a single line in the file with a line such as: .so man3\fclose.3s This is the manpage for fflush(3S). It uses the manpage for fclose(3S). Someday, I may post manpages for sections 2 (bios, xbios, gemdos) and possibly section 3 (dlibs, gemlib, etc). Don't hold your breath, though :-). Enjoy... -Bill Rosenkranz rosenkra AT convex DOT com @EOF set `sum $sumopt man/README.all <<'@EOF' README (man, whatis, 95/06/18) ------------------------------ someone (stanb AT netcom DOT com) had asked for a man(1) command for reading manpages. i am posting such a system which includes: man - read online manpages apropos - list relevant manpages on a given topic (same as "man -k word") whatis - give 1-line description of a command (same as "man -f word") whatisin - list information about what is in sections of the manual mkwhatis - tool to help build whatis database note that man does not have its own pager. man calls the pager and gives it a filename. what man does is find the file (in known places) and figures out what to run (pager, whatis, apropos, etc.). in this regard it is really pretty simple minded. the hard part is getting, organizing, formatting, and maintaining the manpages. for example, i have hundreds of manpages on my systems. the typical unix system might have over a thousand manpages. these programs function more or less the same as the unix (BSD) commands with some exceptions: - man does not invoke nroff. your manpages should be preformatted. - every unix flavor has its own way of doing man so some of the switches on these commands may not correspond with all unix (or posix) ways of dealing with this. - the whatis database itself is different than how unix does it. but it is similar, and no two unix systems do it the same anyway. as it stands, these programs assumes the following directory structure: c:\usr\man main location of manpages, whatis db, etc c:\usr\man\man[0-9lno] dirs containing *unformatted* manpages) c:\usr\man\cat[0-9lno] dirs containing *formatted* manpages) c:\usr\man\whatis._?_ whatis databases for each section (you have to build these based on your collection of manpages) c:\usr\man\whatisin.___ whatisin database man will ONLY look in the cat* directories, and does not format the manpages. you will need nroff for this (cawf, groff, etc). i also have an nroff that i wrote years ago that is PD. or you can format the manpages on a unix system and download them to your PC. everything is configurable, both in the source and via the environment. for example, the c:\usr\man path can be overridded with: - setting environment variable MANPATH - using the commandline switch "-M path" on each command - changing the executables with a binary editor (i have left space in the source for such patches) - changing the source and recompiling caveats: - i am providing this free, with no restrictions. it is 100% my code (does not contain any unix code). - i will not help in any way to fix anything or add new features. this system runs fine under both Unix and on my atari ST (with gcc) so it should port easily, though i have not tried it under DOS or with djgpp. - i will not reformat the source to correspond to someone's notion of style. this is my prefered style, after 10 years of C coding and 20 years of fortran coding. :-) - if you don't like it, either a) fix it yourself, or b) don't use it. it is free, after all. Install: - Unpack everything into separate directories (./man, ./whatis). - The files are all ascii (no binary files). there are no CF-LF (just LF) so if you need CR-LF, you have to fix this yourself. - go to each dir (./man and ./whatis) and look at the makefile. change (at least) the following for your particular setup: CC how to invoke compiler LD how to link .o files MANTOP main location to place manpages (install) MANDIR specific location for manpage source CATDIR specific location for formatted manpages BINDIR location to install executables (man, whatis, etc) DEFS in man, you should specify what you have available (eg, if you have ul(1) and want the -ul switch to function, define HAS_UL). you probably want to define MSDOS, __GNUC__, and possibly undefine unix. in general, check all the macros in upper case in the makefile. note that i could have used sed in the makefile to patch names in the program, but i don't know how good make is on the PC. - man invokes the PAGER and other programs via the system(3) call. on unix (and on my atari), system will search PATH for executables so you don't need a full path. if this is not the case with djgpp, then you will have to alter ./man/man.c to build a full path for executing PAGER, cat, ul, whatis, apropos, etc. - type: make all will build the executables make install will install the execs and manpages make clobber will clean up after the make all. you may also consider doing "make dirs" before make install when building man. this creates the directory structure. you should do man before whatis. - if successful, you should be all set. i have provided formatted manpages (man.1, whatis.1, whatis.5, apropos.1, whatisin.1) from the manpage sources (man.man, whatis.man, whatis.ma5, etc). these were piped through "ul -t dumb" to remove any bold/underline escape sequences. so the formatted manpages are pure ascii. if you have a PAGER that groks how to handle nroff bold, etc, then you may want to reformat the manpages. you should at a minimum build man. it will allow you to read manpages. if you are up for it, the whatis capability might be desirable. whatis contains a 1-line description of every manpage you have on your system. for more information, see the file ./whatis/whatis.5 and whatis.1. note: i have not included any manpages here other than those for these programs themselves. don't ask me for a manpage on ls(1). Environment: these programs recognize several environment variables: MANPAGER man if set, this pager is used by man. on my atari, i have a special pager that resets fonts, based on what -T does in nroff on my system. this gives me bold, etc. PAGER man if MANPAGER is not set, this pager is used. the default is less. MANPATH man, location of the manpages, top level. the whatis default is c:\usr\man. at the moment, MANPATH apropos is a single path, not a list. whatisin for more, grep the sources for "getenv" or read the manpages. note that man will invoke other programs as follows (using system(3)): man file PAGER man -k word apropos man -f name whatis you can also invoke apropos and whatis by themselves, of course. that's about all i have time for. have fun... -bill rosenkranz rosenkra AT convex DOT com @EOF set `sum $sumopt man/manifest <<'@EOF' README.all readme for man and whatis (top level) README readme for man makefile makefile for man man.1 formatted manpage for man man.c man source man.man unformatted manpage for man (nroff -man format) manifest this file @EOF set `sum $sumopt man/makefile <<'@EOF' # makefile for man # # date: Sat Jan 19 04:08:46 1991 # version: 2.0 # # # set this to executable file extension, if necessary (eg, .exe for MSDOS, # .ttp for atari) # EXE = SECT = 1 TARGET = man$(EXE) MANPAGE = man.$(SECT) MANSRC = man.man HEADERS = SRCS = $(HEADERS) man.c OTHERS = readme makefile $(MANSRC) DISTFILES = $(OTHERS) $(SRCS) OBJS = man.o # set CC to the command needed to compile a file (to a .o file). # set LD to the command needed to link .o files. # #CC = gcc -v -z -Wall -Ic:/u/gcc/include #LD = gcc -v -z -Wall -Lc:/u/gcc/lib -nostdlib c:/u/gcc/lib/crt0.o CC = cc -Aa LD = cc -Aa # defines based on what you have: # -DHAS_CAT yes, i have cat$(EXE) # -DHAS_UL yes, i have ul$(EXE) # -DHAS_WHATIS yes, i have whatis$(EXE) # -DHAS_APROPOS yes, i have apropos$(EXE) # -DLONG_SECT use longer list for things like "local" # -DUSE_INDEX if you need index/rindex instead of strchr/strrchr # -Datarist for Atari ST # -DMSDOS for PC # -Dunix for unix systems (or unix-like) # DEFS = -DHAS_CAT -DHAS_UL -DHAS_WHATIS -DHAS_APROPOS -DLONG_SECT # set ARCH for things like -mshort. # set OPT potentially to -O. # set libs to list of libraries needed in link (eg, -lc). # ARCH = OPT = CFLAGS = $(ARCH) $(OPT) $(DEFS) LDFLAGS = $(ARCH) LIBS = # set BINDIR to the place where you want the executable installed. # set MANDIR to the place where man's manpage will be installed (the # directory must exist; consider doing "make dirs" before "make install") # include a trailing / (or \) for both BINDIR and MANDIR. # #SLASH =\\ #BINDIR = c:\usr\bin #MANTOP = c:\usr\man #MANDIR = $(MANTOP)$(SLASH)man$(SECT) #CATDIR = $(MANTOP)$(SLASH)cat$(SECT) SLASH =/ BINDIR = /mnt/rosenkra/test/bin MANTOP = /mnt/rosenkra/test/man MANDIR = $(MANTOP)$(SLASH)man$(SECT) CATDIR = $(MANTOP)$(SLASH)cat$(SECT) # install commands # INST_BIN = cp -p INST_MAN = cp -p RM = rm -f # directions... # directions: @echo type "make all" to built $(TARGET) @echo type "make dirs" to create $(MANDIR) directories @echo type "make install" to build/install $(TARGET) @echo type "make clean" to remove objects @echo type "make clobber" to remove objects and $(TARGET) @echo these should be done in this order # main target... # all: $(TARGET) $(TARGET): $(OBJS) $(LD) $(LDFLAGS) -o $(TARGET) $(OBJS) $(LIBS) # manpage (use built-in .man.cat rule)... # manpage: $(MANPAGE) $(MANPAGE): $(MANSRC) nroff -man $(MANSRC)|ul -t dumb|cat -s >$(MANPAGE) # create directories # dirs: install_dirs install_dirs: mkdir $(MANTOP) mkdir $(MANTOP)$(SLASH)cat0 $(MANTOP)$(SLASH)man0 mkdir $(MANTOP)$(SLASH)cat1 $(MANTOP)$(SLASH)man1 mkdir $(MANTOP)$(SLASH)cat2 $(MANTOP)$(SLASH)man2 mkdir $(MANTOP)$(SLASH)cat3 $(MANTOP)$(SLASH)man3 mkdir $(MANTOP)$(SLASH)cat4 $(MANTOP)$(SLASH)man4 mkdir $(MANTOP)$(SLASH)cat5 $(MANTOP)$(SLASH)man5 mkdir $(MANTOP)$(SLASH)cat6 $(MANTOP)$(SLASH)man6 mkdir $(MANTOP)$(SLASH)cat7 $(MANTOP)$(SLASH)man7 mkdir $(MANTOP)$(SLASH)cat8 $(MANTOP)$(SLASH)man8 mkdir $(MANTOP)$(SLASH)cat9 $(MANTOP)$(SLASH)man9 touch install_dirs # to install it... # install: install_dirs install_bin install_man install_bin: $(TARGET) $(INST_BIN) $(TARGET) $(BINDIR)$(SLASH)$(TARGET) touch install_bin install_man: $(MANPAGE) $(INST_MAN) $(MANSRC) $(MANDIR)$(SLASH)$(MANPAGE) $(INST_MAN) $(MANPAGE) $(CATDIR)$(SLASH)$(MANPAGE) touch install_man # others... # clean: $(RM) core $(OBJS) errs clobber: clean $(RM) $(TARGET) # dependencies... # man.o: man.c @EOF set `sum $sumopt man/man.1 <<'@EOF' MAN(1) MAN(1) NAME man - read online documentation SYNOPSIS man [- [-ul]] [-s sect[subs]] [-M path] [-m path] [-e] [sect[subs]] name... man -f file... man -k keyword... DESCRIPTION The man command finds and displays information in the online documentation set. When the standard output is a terminal, man pipes its output through less(1) or the name of the command specified with the MANPAGER or PAGER environment variables. OPTIONS The following command line options are recognized: - Pipes the output through cat(1) rather than less(1) or PAGER. - -ul Use ul(1) rather than cat(1). -M path Specifies a directory tree in which to search. By default, man searches in c:\usr\man under MSDOS or on the Atari ST or /usr/man under Unix, or the directory specified by the MANPATH environment variable, the standard location for online documentation. The MANPATH variable should have a single path name at the present time (eventually, it will support a colon-separated list of locations). This option assumes path is the root of a normal directory structure. For compatibility with some Unix man systems, you can use -P as well as -M. -m path Specifies a directory in which to search. This option does not use a directory tree. Files are searched only in the directory specified by path. This option is useful for debugging new manpages. For example, assuming you are working on a manpage named mycmd.1, you can do this: man -m . 1 mycmd -e Find every manpage concerning the given name regardless of section. It is expected that a normal exit from the pager will result in an exit status of 0 (in which case the search is continued in other sections). An abnormal exit should result in a nonzero exit status and the search is then terminated. -s sect[subsect] Specifies a section and subsection similar to the 4.2 BSD UNIX - 1 - Formatted: June 18, 1995 MAN(1) MAN(1) Programmer's Manual (as explained below) in which to search. If no section is specified, man searches through all of the sections. Example: man -s 3s fopen. sect As an alternative to -s, you can specify the section (and optional subsection) as the first argument. Example: man 3s fopen. name Searches for documentation files associated with the specified name. -f name Displays a one line synopsis of each online documentation file whose names match the specified word (equivalent to the whatis(1) command). For example, man -f chmod will give entries for both chmod(1) and chmod(2). Note that man invokes whatis(1) in this case, so it should be found in the path (see ENVIRONMENT). -k keyword Displays a one line synopsis of each online documentation file whose name or description contains the specified keyword (equivalent to the apropos(1) command). Note that man invokes apropos(1) in this case, so it should be found in the path (see ENVIRONMENT). ENVIRONMENT The following environment variables are recognized: MANSECT This can be used to alter the search order and to customize subsections. The default is equivalent to: setenv MANSECT 108234576,tcgesla,,s,mgbxl,msvcxgl,dkvscm,,, This means the major sections (man1, etc.) are searched in the order man1, man0, man8, etc. For each section, you can also provide a list of subsections which must correspond in the remaining list. In this case man1 subsections are t,c,g,e,s,l, and a; there are no subsections for man0; etc. The first entry (the section list) must consist of numbers from 0 to 9 only. Numbers can be skipped. The default search order is oriented toward users. To speed up the search, a casual programmer might perfer: 325481760,gsmcvxl,mgbxl,,dkvscm,s,tcgesla,,, while a Unix programmer might prefer: 235481760,mgbxl,csmxvlg,,dkvscm,s,tcgesla,,, - 2 - Formatted: June 18, 1995 MAN(1) MAN(1) MANPATH,MANDIR Location of main manual direcotry, where subdirectories are to be found. Man uses (in order of priority) the path specified with -M, the MANPATH specified, or the built-in default (c:\usr\man or /usr/man). MANPAGER Name of prefered pager. Use this pager if you have compressed manpages (see manpager(1)). Man will use first MANPAGER, if found, then PAGER, if found. If neither are found, it uses c:\usr\bin\less. PAGER Name of secondary pager to replace less(1). Use this if you do not have manpages generated with font changes (see nroff(1)). Either MANPAGER or PAGER should be defined. The search order is MANPAGER then PAGER. Note that BINDIR and TMPDIR are not currently used. SECTION NAMES By convention, the "sections" of the manual are (see whatisin(1) as well): Sect Section Name Description ---- ------------- -------------------------------------- 0 General overview of features and documentation 1 Commands user commands 2 System Calls low-level system library calls (C) 3 Library Calls standard user calls (C) 4 Special Files special system files and hardware 5 File formats things like arc(1) file formats 6 Games games manual 7 Miscellaneous miscellaneous information 8 Administration system administration commands In addition, this man recognizes the following section names: local files specific to local system new files added since current software release old files from previous software release gnu GNU files (gcc typically) paper misc formal papers doc misc documentation The search order, if no section is specified, is: 108234576 In addition to sections, there are a number of subsections possible, though these files do not reside in a special directory. The - 3 - Formatted: June 18, 1995 MAN(1) MAN(1) subsection name is simply appended to the file name. Example: fopen.3s resides in $MANPATH\man3, the section is 3 (libraries) and the subsection is s, stdio. Here is the subsection search order for subsections in each section (the square brackets mean a choice of each character contained in them, in that order): man1\*.1[tcgesla] util & text,com,graphics,edit,shell,lang archival man0\*.0 man8\*.8[s] util & system man2\*.2[mgbxl] system & mint,gemdos,bios,xbios,lineA man3\*.3[msvcxgl] C lib & math,stdio,sysV,compat,extra gem(aes/vdi),local man4\*.4[dkvscm] general & disk,keyboard,video,sound,chips memory man5\*.5 man7\*.7 man6\*.6 NOTES To save disk space, you can "source" other files by including the nroff(1) directive .so in a file as the first line. In this case, the first line should start with .so followed by at least one space, then the file to use instead of the actual manpage. For example, the manpage for feof.3s (in $MANPATH\man3) contains the single line: .so man3\ferror.3s which will cause man to display the contents of ferror.3s instead. Note the relative path (relative to MANPATH, by default c:\usr\man). In this way, numerous manpages can refer to a single (larger) file. Do not compress files with source lines as man only checks for this line if it finds a file which is not compressed. Note that you should only compress files for viewing with a pager that supports reading compressed files (e.g., manpager(1)) and must set the MANPAGER environment variable as well. You can also specify just a file name for sourcing (without relative path): .so ferror.3s and man will use the relative path of the file containing this line. FILES c:\usr\man root of standard manual page directory tree c:\usr\man\man*\* manual entries c:\usr\man\whatis table of contents and keyword database SEE ALSO apropos(1), cat(1), less(1), manpager(1), nroff(1), what(1), - 4 - Formatted: June 18, 1995 MAN(1) MAN(1) whatis(1), whatisin(1), whereis(1), man(7) AUTHOR Bill Rosenkranz rosenkra AT convex DOT com VERSION man v3.0.2 92/10/11 rosenkra - 5 - Formatted: June 18, 1995 @EOF set `sum $sumopt man/man.c <<'@EOF' static char *rcsid = "$Id: man.c,v 1.4 1992/10/12 09:59:02 rosenkra Exp $"; static char *version = "man v3.0.2 92/10/11 rosenkra AT convex DOT com"; static char *myname = "man"; /* * man - read on-line documentation * * This version uses "manpager" or "less" for paging. It does NOT * call nroff (ie, manpages must be preformatted -- see SUBDIRBASE * macro below). * * search order (based on my manpage nomenclature): * * man1/*.1[tcgesla] cmds util & text,com,graphics, * edit,shell,lang, archival * man0/*.0 gen * man8/*.8[s] admin util & system * man2/*.2[b] syslib system & bios * man3/*.3[msvcxl] libs C lib & math,stdio,sysV, * compat,extra,local * man4/*.4[dkvscm] h/w gen & disk,keyboard,video, * sound,chips,memory * man5/*.5 files * man7/*.7 misc * man6/*.6 games * * these are seached only if given sections "local", "new", "old": * * manl/*.l local * mann/*.n new * mano/*.o old */ /* * $Log: man.c,v $ * Revision 1.4 1992/10/12 09:59:02 rosenkra * basically same as last version (which was premature). fix a couple * of bugs. * * Revision 1.3 1992/10/11 16:21:24 rosenkra * this is v3.0.2. it adds a -P alias for -M, ability to source files * with either .so manx/file.x or .so file.x; also added was MANSECT * env var. help (usage) was beefed up. all reading of env now done in * env_inquiry(). * * Revision 1.2 1992/07/27 10:03:38 rosenkra * added ability to review all manpages of given name regardless * of section (-e). also do env checks before arg parsing. * * Revision 1.1 1992/07/27 02:03:58 rosenkra * Initial revision * */ #ifdef __hpux /* HPUX for some reason needs this with */ #define _INCLUDE_POSIX_SOURCE 1 #define unix 1 #endif #include #include #if defined(unix) || defined(__unix) #include #include #include #include #include #elif defined(__GNUC__) && defined(MSDOS) #include #include #include #include #else #include #include extern char *index (); extern char *getenv (); #endif #ifdef USE_INDEX #include #define strchr index #define strrchr rindex #endif /* * deal with MSDOS */ #if defined(unix) || defined(__unix) #define SLASH_CHR '/' #define SLASH_STR "/" #else #define SLASH_CHR '\\' #define SLASH_STR "\\" #endif /* * common (default) places. note the patch space... */ #if defined(atarist) || defined(MSDOS) # define MANDIR "c:\\usr\\man\0\0\0<------MANDIR_patch_space------->\0" # define BINDIR "c:\\usr\\bin\0\0\0<------BINDIR_patch_space------->\0" # define TMPDIR "c:\\tmp\0\0\0<---------TMPDIR_patch_space--------->\0" #else /* assume unix */ # define MANDIR "/usr/man" # define BINDIR "/usr/bin" # define TMPDIR "/tmp" #endif /* * default pager (we invoke this with system()): */ #if defined(unix) || defined(__unix) # define MORE "less" /* could use -m -s also */ #elif defined(atarist) # define MORE "less.ttp\0\0\0<--------MORE_patch_space----------->\0" #elif defined(MSDOS) # define MORE "less.exe\0\0\0<--------MORE_patch_space----------->\0" #endif /* * other commands we may run */ #ifdef HAS_CAT # if defined(unix) || defined(__unix) # define CAT "cat -s" /* for '-' opt, use "cat -s" */ # elif defined(atarist) # define CAT "cat.ttp\0\0\0<---------CAT_patch_space------------>\0" # elif defined(MSDOS) # define CAT "cat.exe\0\0\0<---------CAT_patch_space------------>\0" # else # undef HAS_CAT # endif #endif #ifdef HAS_UL # if defined(unix) || defined(__unix) # define UL "ul -t dumb" /* for '- -ul' opt (don't use pager) */ # elif defined(atarist) # define UL "ul.ttp\0\0\0<----------UL_patch_space------------->\0" # elif defined(MSDOS) # define UL "ul.exe\0\0\0<----------UL_patch_space------------->\0" # else # undef HAS_UL # endif #endif #ifdef HAS_APROPOS # if defined(unix) || defined(__unix) # define APROPOS "apropos" # elif defined(atarist) # define APROPOS "apropos.ttp\0\0<--------APROPOS_patch_space------->\0" # elif defined(MSDOS) # define APROPOS "apropos.exe\0\0<--------APROPOS_patch_space------->\0" # else # undef HAS_APROPOS # endif #endif #ifdef HAS_WHATIS # if defined(unix) || defined(__unix) # define WHATIS "whatis" # elif defined(atarist) # define WHATIS "whatis.ttp\0\0<--------WHATIS_patch_space--------->\0" # elif defined(MSDOS) # define WHATIS "whatis.ttp\0\0<--------WHATIS_patch_space--------->\0" # else # undef HAS_WHATIS # endif #endif /* * define sections and subsections. sections are dirs like "man1" and * "cat1". subsections are used in names of manpages within the dir * (eg, "foo.1t"). */ #define ALLSECT "108234576" /* order to look through sections */ #define SUBSEC0 "" /* subsec to try in each section */ #define SUBSEC1 "tcgesla" #define SUBSEC2 "g" #define SUBSEC3 "msvcxl" #define SUBSEC4 "dkvscm" #define SUBSEC5 "" #define SUBSEC6 "" #define SUBSEC7 "" #define SUBSEC8 "s" #define SUBSEC9 "" /* * deal with compressed files */ #if defined(MSDOS) #define ZSUFFIX "Z" /* for compressed files */ #else #define ZSUFFIX ".Z" /* for compressed files */ #endif #define ZSWITCH "-z" /* for MANPAGER to read compressed file */ /* * files come from MANPATH/cat*. normally, unix man will first * check for preformatted manpages in /usr/man/cat* dirs. if they * are not found, nroff is run on /usr/man/man* files. with this * man, however, we are assuming that manpages have already been * formatted. by convention, this means that the dirs to search * should be named 'cat[1-8]' and not 'man[1-8]'. if you don't * care about this, make SUBDIRBASE "man". */ #define SUBDIRBASE "cat" #ifdef dbg # undef dbg #endif #define dbg(x) if(debugging_G)printf x , fflush(stdout) /* * misc macros */ #ifdef lastchar # undef lastchar #endif #ifdef plastchar # undef plastchar #endif #define lastchar(s) ((s)[strlen(s)-1]) /* last char in a string */ #define plastchar(s) &((s)[strlen(s)-1]) /* ptr to it */ #define PLEN 256 /* max path length */ /* * globals: */ #ifdef HAS_UL int ul4cat_G = 0; /* use ul instead of cat */ #endif int every_G = 0; /* every section */ int debugging_G = 0; int hasmanpager_G = 0; /* if pager is MANPAGER */ int usermanpath_G = 0; /* if -M */ int nopager_G = 0; /* if no pager of any kind */ int pthpager_G = 0; /* if pager has a full path */ int envmansect_G = 0; /* if MANSECT in env */ char *manpath_G = 0L; char mpbuf[PLEN]; char *binpath_G = 0L; char bpbuf[PLEN]; char *tmppath_G = 0L; char tpbuf[PLEN]; char *pager_G = 0L; char pgbuf[PLEN]; char cmdbuf_G[512]; int section_G = 0; /* section, ascii char */ int subsec_G = 0; /* subsection, ascii char */ /* * set up default search lists. these can be overridden with the env: * * setenv MANSECT 108234576,tcgesla,,s,mgbxl,msvcxgl,dkvscm,,, */ char *allsect = ALLSECT; char *subsec0 = SUBSEC0; char *subsec1 = SUBSEC1; char *subsec2 = SUBSEC2; char *subsec3 = SUBSEC3; char *subsec4 = SUBSEC4; char *subsec5 = SUBSEC5; char *subsec6 = SUBSEC6; char *subsec7 = SUBSEC7; char *subsec8 = SUBSEC8; char *subsec9 = SUBSEC9; #ifdef LONG_SECT char *longsect[] = {"local", "new", "old", "gnu", "paper", "doc", (char *) 0}; #endif /* * functions: */ int set_section (char *); int find_manpage (char *); int do_it (char *, int); char *so_line (char *); void env_inquiry (void); void usage (int); /*------------------------------*/ /* main */ /*------------------------------*/ void main (int argc, char *argv[]) { int retcode; char **av; int ac; /* * quick scan of args to find debug since we need it first. * note that argc and argv are not changed... */ ac = argc; av = argv; for (ac--, av++; ac > 0 && **av == '-'; ac--, av++) { if (*(*av+1) == 'd') { debugging_G = 1; break; } } /* * check environment (cmdline overrules things) */ env_inquiry (); /* * must have an arg */ argc--, argv++; if (argc < 1) { usage (1); } /* * parse cmdline. it overrides defaults and environment... */ while (argc > 0 && **argv == '-') { switch (*(*argv+1)) { case 0: /* use cat (just a "-") */ #ifdef HAS_CAT nopager_G++; #else fprintf (stderr, "%s: cat and not supported\n"); usage (1); #endif break; case 'e': /* every section */ every_G++; break; case 'P': case 'M': /* reset path (-M path) */ /* this is manpath/man[1...] */ argc--, argv++; manpath_G = *argv; break; case 'm': /* reset path (-m path) */ /* this is manpath alone */ /* use "-m ." for cwd */ argc--, argv++; manpath_G = *argv; usermanpath_G = 1; break; case 'u': /* use ul(1) for cat */ #ifdef HAS_UL ul4cat_G++; #else fprintf (stderr, "%s: ul not supported\n"); usage (1); #endif break; case 's': /* specific section */ switch (--argc) { case 0: /* Nothing follows -s */ fprintf (stderr, "%s: must specify a section with -s\n", myname); usage (1); case 1: /* Section, but no man page */ fprintf (stderr, "%s: must specify an item from section %s\n", myname, *argv); usage (1); default: /* * if valid section, set_section sets * section_G */ if (set_section (*++argv) == 0) { fprintf (stderr, "%s: unknown section: %s\n", myname, *argv); usage (1); } break; } break; case 'f': /* whatis */ case 'w': #ifdef HAS_WHATIS #if defined(__GNUC__) || defined(unix) || defined(__unix) strcpy (cmdbuf_G, WHATIS); #else strcpy (cmdbuf_G, binpath_G); if (lastchar (cmdbuf_G) != SLASH_CHR) strcat (cmdbuf_G, SLASH_STR); strcat (cmdbuf_G, WHATIS); #endif /*__GNUC__*/ argc--, argv++; while (argc) { strcat (cmdbuf_G, " "); strcat (cmdbuf_G, *argv); argc--, argv++; } dbg(("whatis, system (%s)\n",cmdbuf_G)); retcode = system (cmdbuf_G); exit (retcode); #else /*!HAS_WHATIS*/ fprintf (stderr, "%s: whatis not supported\n"); usage (1); #endif /*HAS_WHATIS*/ break; case 'k': /* apropos */ case 'a': #ifdef HAS_APROPOS strcpy (cmdbuf_G, APROPOS); #if defined(__GNUC__) || defined(unix) || defined(__unix) strcpy (cmdbuf_G, APROPOS); #else strcpy (cmdbuf_G, binpath_G); if (lastchar (cmdbuf_G) != SLASH_CHR) strcat (cmdbuf_G, SLASH_STR); strcat (cmdbuf_G, APROPOS); #endif /*__GNUC__*/ argc--, argv++; while (argc) { strcat (cmdbuf_G, " "); strcat (cmdbuf_G, *argv); argc--, argv++; } dbg(("apropos, system (%s)\n",cmdbuf_G)); retcode = system (cmdbuf_G); exit (retcode); #else /*!HAS_APROPOS*/ fprintf (stderr, "%s: apropos not supported\n"); usage (1); #endif /*HAS_APROPOS*/ break; case 'h': /* help */ usage (0); break; case 'd': /* turn on debugging */ debugging_G = 1; break; case 'v': /* version */ printf ("%s\n", version); exit (0); break; case '-': switch (*(*argv+2)) { case 'v': /* --version */ printf ("%s\n", version); exit (0); break; case 'h': /* --help */ usage (0); break; } break; } argc--, argv++; } /* * If there are multiple words, no -s seen above, and the first * word is a valid section name, read the subsequent man pages * from that section. set_section will set section_G if *argv is a * bona fide section. * * this also should make sure arg is a digit and only [] * but will fail on actual manpages named something like "1.1". * hopefully these are non-existent. */ if ((argc > 1) && (section_G == 0) && (set_section (*argv) || (isdigit(**argv) && (strlen(*argv) < 3)))) { argc--; argv++; } /* * move to correct directory. no need to move if it is cwd... */ if (strcmp (manpath_G, ".") && (chdir (manpath_G) < 0)) { fprintf (stderr, "%s: can't chdir to %s.\n", myname, manpath_G); exit (1); } /* * check if stdout not a tty an no pager. */ #if 0 if (nopager_G == 0 && !isatty (1)) nopager_G++; #endif dbg(("nopager_G = %d, isatty(1) = %d\n", nopager_G, (int) isatty(1))); /* * do it for all remaining tokens */ while (argc-- > 0) { retcode = find_manpage (*argv++); if (retcode) { fprintf (stderr, "%s: failed!!!\n", myname); exit (retcode); } } exit (0); } /*------------------------------*/ /* set_section */ /*------------------------------*/ int set_section (char *cptr) { /* * routine to set section_G and subsec_G from a given section name, * returning the letter of the section used or a zero if an unfamiliar * keyword is used. */ int sec; int ret; int i; if (strlen (cptr) > 2) { /* * section is 3 or more char */ #ifdef LONG_SECT for (i = 0; longsect[i]; i++) { if (!strcmp (longsect[i], cptr)) return (section_G = (int) (*longsect[i])); } #else if (!strcmp (cptr, "local")) return ((int) (section_G = 'l')); if (!strcmp (cptr, "new")) return ((int) (section_G = 'n')); if (!strcmp (cptr, "old")) return ((int) (section_G = 'o')); #endif /* * If we reach here, none of the special names match, * and we'll return a zero (error) on the other side of * the else. */ section_G = '\0'; subsec_G = '\0'; ret = 0; } else { /* * section is 2 or less char. subsec could be 0 */ section_G = (int) cptr[0]; subsec_G = (int) cptr[1]; ret = section_G; /* * crude check for legality: section must be 0-8, subsect * must be a letter */ sec = section_G - '0'; /*!!!*/ if (sec < 0 || sec > 9) ret = 0; if (subsec_G) { if (!isalpha (subsec_G)) ret = 0; } } /* * ret is 0 if invalid section, else section number */ return (ret); } struct stat sbuf; /*------------------------------*/ /* find_manpage */ /*------------------------------*/ int find_manpage (char *name) { /* * find the manpage file */ char c_sectn; char work[PLEN]; int stflag; int last; char seclist[30]; char sublist[30]; char *psec; char *psub; char *ps; char *cp; int iscompressed = 0; int found = 0; /* * set up template (we removed any trailing '/' already) * * if usermanpath is set, we read from that dir and don't assume * any "normal" dir structure (-m option). otherwise we do normal * (or -M option). */ if (usermanpath_G) sprintf (work, "%s%s%s.x", manpath_G, SLASH_STR, name); else sprintf (work, "%s%s%sx%s%s.x", manpath_G, SLASH_STR, SUBDIRBASE, SLASH_STR, name); /* * index of last char in template. this should be section. * work[last+1] is subsection, and work[last+2] will be ZSUFFIX * if compressed and we are using MANPAGER. */ last = strlen (work) - 1; dbg(("template, work = |%s|, last = %d\n", work, last)); /* * set up list of sections to search. either use section_G or * allsect */ if (section_G) { seclist[0] = (char) section_G; seclist[1] = '\0'; } else { strcpy (seclist, allsect); } psec = seclist; if (subsec_G) { sublist[0] = (char) subsec_G; sublist[1] = '\0'; psub = sublist; } else psub = (char *) NULL; dbg(("psec = |%s|, psub = |%s|\n", psec, (psub ? psub : "NULL"))); /* * find manx string in template. ps points to the '/' */ if (!usermanpath_G) { char tmpstringx[PLEN]; tmpstringx[0] = SLASH_CHR; strcpy(&tmpstringx[1], SUBDIRBASE); for (ps = work; *ps; ps++) { if (!strncmp (ps, tmpstringx, 4) && *(ps+5) == SLASH_CHR) break; } } /* * loop thru all sections. could be only specified section */ for (c_sectn = *psec; c_sectn; c_sectn = *++psec) { /* * fill in template: man_/xxx._\0\0 (no sub yet) */ if (!usermanpath_G) ps[4] = c_sectn; work[last] = c_sectn; work[last + 1] = 0; work[last + 2] = 0; work[last + 3] = 0; /* * if a subsection was specified, skip past this... */ if (subsec_G) goto SEARCH; /* * does this file exist? */ dbg(("try |%s|...\n", work)); if ((stflag = stat (work, &sbuf)) >= 0) { /* * yes...exit this for loop */ if (every_G) { /* * PAGER should support ^C exit. it should * exit with status 1 in that case (and * do_it() would also return 1). it is not * an error, however, to exit this way but * we return (with 0) so next item will * be searched. */ found++; if (do_it (work, iscompressed)) return (0); goto NEXT_LOOP; } else goto FOUND_ONE; } /* * no...try looking for compressed version */ if (hasmanpager_G) { dbg(("not found, try compressed file...\n")); #if 0 work[last + 1] = ZSUFFIX; work[last + 2] = '\0'; work[last + 3] = '\0'; #endif strcpy(&work[last+1], ZSUFFIX); dbg(("try |%s|...\n", work)); if ((stflag = stat (work, &sbuf)) >= 0) { /* * yes... */ iscompressed = 1; if (every_G) { found++; if (do_it (work, iscompressed)) return (0); goto NEXT_LOOP; } else goto FOUND_ONE; } work[last + 1] = '\0'; /* reset! */ dbg(("not found...\n")); } SEARCH: ; /* * still not found...look for subsections in manx * * set up subsect string */ if (subsec_G) cp = psub; else { /* * take the default subsections for a section... */ switch (work[last]) { case '0': cp = subsec0; break; case '1': cp = subsec1; break; case '2': cp = subsec2; break; case '3': cp = subsec3; break; case '4': cp = subsec4; break; case '5': cp = subsec5; break; case '6': cp = subsec6; break; case '7': cp = subsec7; break; case '8': cp = subsec8; break; case '9': cp = subsec9; break; default: cp = ""; break; } } dbg(("not found, try subsect, cp = |%s|\n", cp)); /* * cycle thru subsections */ while (*cp) { /* * do we find one now? */ work[last + 1] = *cp++; work[last + 2] = '\0'; dbg(("try |%s|...\n", work)); if ((stflag = stat (work, &sbuf)) >= 0) { /* * yes... */ if (every_G) { found++; if (do_it (work, iscompressed)) return (0); goto NEXT_LOOP; } else goto FOUND_ONE; } /* * still no...try compressed... */ if (hasmanpager_G) { dbg(("not found, try compressed file...\n")); #if 0 work[last + 2] = ZSUFFIX; work[last + 3] = '\0'; #endif strcpy(&work[last+2], ZSUFFIX); dbg(("try |%s|...\n", work)); if ((stflag = stat (work, &sbuf)) >= 0) { /* * yes... */ iscompressed = 1; if (every_G) { found++; if (do_it (work, iscompressed)) return (0); goto NEXT_LOOP; } else goto FOUND_ONE; } work[last + 2] = '\0'; /* reset! */ dbg(("not found...\n")); } /* we give up. try next subsection, if any... */ } /* we give up. try next section, if any... */ NEXT_LOOP: ; } if (every_G) { if (found) return (0); else printf ("%s: no manual entry for %s. try man local %s\n", myname, name, name); } else { if (section_G == 0) printf ("%s: no manual entry for %s. try man local %s\n", myname, name, name); else printf ("%s: no entry for %s in section %c%c of the manual.\n", myname, name, (char) section_G, (subsec_G ? (char) subsec_G : ' ')); } return (1); FOUND_ONE: ; dbg(("Found: %s(%x), iscompressed = %d\n",work,stflag,iscompressed)); return ((int) do_it (work, iscompressed)); } /*------------------------------*/ /* do_it */ /*------------------------------*/ int do_it (char *cp, int iscompressed) { char cmdpath[256]; char cmd[256]; char *so; /* * open the file, look for ".so file" as first line. use that file * instead. only one level of this nesting is possible (the * included file can't include, too). do this only if file not * compressed! */ dbg(("enter do_it, cp = |%s|...\n", cp)); if (!iscompressed) { so = so_line (cp); if (so) { cp = so; dbg(("so_line found something, new cp = |%s|...\n",cp)); } } /* * set up command path (for paging) */ #if defined(__GNUC__) || defined(unix) || defined(__unix) cmdpath[0] = '\0'; #else strcpy (cmdpath, binpath_G); if (lastchar (cmdpath) != SLASH_CHR) strcat (cmdpath, SLASH_STR); #endif if (!nopager_G) { /* * use pager. if compressed, add correct switch (note: * iscompressed set only if hasmanpager is true) */ if (iscompressed) { sprintf (cmd, "%s%s %s %s", (pthpager_G ? "" : cmdpath), pager_G, ZSWITCH, cp); } else { sprintf (cmd, "%s%s %s", (pthpager_G ? "" : cmdpath), pager_G, cp); } } #ifdef HAS_UL else if (ul4cat_G) { /* * use ul rather than cat if no pager */ sprintf (cmd, "%s%s %s", cmdpath, UL, cp); } #endif #ifdef HAS_CAT else { /* * use cat if no pager */ sprintf (cmd, "%s%s %s", cmdpath, CAT, cp); } #endif /* * invoke the pager (or cat or ul) */ dbg(("system (%s)\n", cmd)); return ((int) system (cmd)); } /*------------------------------*/ /* so_line */ /*------------------------------*/ char *so_line (char *fname) { /* * read first line from found file, looking for ".so " followed by * alternate sourced file. if found, returns ptr to the new name. * otherwise, null. * * the file name should include the path of the subsection, e.g. * the file for degas.5 (in man5) contains: * * .so man5/picture.5 * * the rest of the file (man5/degas.5) is ignored. * * new: now can also handle * * .so picture.5 * * fname comes in with man5/degas.5 so use the leading path. */ static char buf[256]; char tbuf[256]; char *so; FILE *stream; char *ps; so = (char *) 0; if ((stream = fopen (fname, "r")) == (FILE *) 0) { printf ("%s: could not open %s to look for .so\n", myname, fname); return (so); } /* * grab first line, delete newline */ fgets (buf, 255, stream); fclose (stream); so = buf; while (*++so) ; *--so = '\0'; /* * is it .so? */ so = buf; if (!strncmp (so, ".so ", 4)) { so += 4; while (*so == ' ' || *so == '\t') so++; dbg(("so_line read |%s|\n", so)); if ((ps = strrchr (so, '\\')) == (char *) 0 && (ps = strrchr (so, '/')) == (char *) 0) { /* * the .so line does not contain manx/name.x so * use path from fname. */ strcpy (tbuf, so); strcpy (so, fname); if (ps = strrchr (so, SLASH_CHR)) { ps++; strcpy (ps, tbuf); } else if (ps = strrchr (so, '/')) { ps++; strcpy (ps, tbuf); } } dbg(("so_line returning |%s|\n", so)); return (so); } else { dbg(("so_line returning NULL\n")); return ((char *) 0); } } /*------------------------------*/ /* env_inquiry */ /*------------------------------*/ void env_inquiry (void) { /* * look up things in environment: * * MANPAGER,PAGER * TEMP,TMPDIR * MANPATH,MANDIR * BINDIR * MANSECT * * setenv MANSECT 108234576 * setenv MANSECT 108234576,tcgesla,,s,mgbxl,msvcxgl,dkvscm,,, */ char *ps; char *pl; char *pd; static char sectbuf[256]; /* * alternate pager from environment. if env has variable MANPAGER * defined, use it as pager (this allows dealing with bold and * italics in manpage, for example). if not, look for PAGER. if * neither is set, use default as defined by macro MORE here. */ if (pager_G == (char *) NULL) { if ((ps = getenv ("MANPAGER")) != (char *) NULL) { strcpy (pgbuf, ps); pager_G = pgbuf; hasmanpager_G = 1; } else if ((ps = getenv ("PAGER")) != (char *) NULL) { strcpy (pgbuf, ps); pager_G = pgbuf; } else pager_G = MORE; } if (pager_G && (strchr (pager_G, ':') || strchr (pager_G, SLASH_CHR))) pthpager_G = 1; dbg(("pager_G = |%s|, pthpager_G = %d\n",(pager_G ? pager_G : "NULL"), pthpager_G)); /* * place to put temp files, if needed (not needed yet...) */ if (tmppath_G == (char *) NULL) { if ((ps = getenv ("TEMP")) != (char *) NULL) { strcpy (tpbuf, ps); tmppath_G = tpbuf; } else if ((ps = getenv ("TMPDIR")) != (char *) NULL) { strcpy (tpbuf, ps); tmppath_G = tpbuf; } else tmppath_G = TMPDIR; } if (tmppath_G && lastchar (tmppath_G) == SLASH_CHR)/* rem trail '/' */ lastchar (tmppath_G) = '\0'; dbg(("tmppath_G = |%s|\n", tmppath_G ? tmppath_G : "NULL")); /* * where man pages are (e.g. /usr/man) */ if (manpath_G == (char *) NULL) { if ((ps = getenv ("MANPATH")) != (char *) NULL) { strcpy (mpbuf, ps); manpath_G = mpbuf; } else if ((ps = getenv ("MANDIR")) != (char *) NULL) { strcpy (mpbuf, ps); manpath_G = mpbuf; } else manpath_G = MANDIR; } if (manpath_G && lastchar (manpath_G) == SLASH_CHR)/* rem trail '/' */ lastchar (manpath_G) = '\0'; dbg(("manpath_G = |%s|\n", manpath_G ? manpath_G : "NULL")); /* * place to find pagers */ if (binpath_G == (char *) NULL) { if ((ps = getenv ("BINDIR")) != (char *) NULL) { strcpy (bpbuf, ps); binpath_G = bpbuf; } else binpath_G = BINDIR; } if (binpath_G && lastchar (binpath_G) == SLASH_CHR)/* rem trail '/' */ lastchar (binpath_G) = '\0'; dbg(("binpath_G = |%s|\n", binpath_G ? binpath_G : "NULL")); /* * finally, deal with MANSECT. this should be last section * since this returns. */ if ((ps = getenv ("MANSECT")) != (char *) NULL) { strcpy (sectbuf, ps); dbg(("MANSECT = |%s|\n", sectbuf)); envmansect_G = 1; pl = ps = sectbuf; while (*ps && *ps != ',') /* find first , */ ps++; if (*ps == '\0') /* if no more list, return */ return; *ps++ = '\0'; /* terminate allsect */ allsect = pl; dbg(("allsect = |%s|\n", allsect)); while (*pl) { dbg(("for sect %c, ", (int) *pl)); pd = ps; switch (*pl) { case '0': subsec0 = ps; goto find_comma; case '1': subsec1 = ps; goto find_comma; case '2': subsec2 = ps; goto find_comma; case '3': subsec3 = ps; goto find_comma; case '4': subsec4 = ps; goto find_comma; case '5': subsec5 = ps; goto find_comma; case '6': subsec6 = ps; goto find_comma; case '7': subsec7 = ps; goto find_comma; case '8': subsec8 = ps; goto find_comma; case '9': subsec9 = ps; find_comma: ; if (*ps == ',') { *ps++ = '\0'; if (*ps == '\0') { dbg(("subsec = empty\n")); return; } dbg(("subsec = empty\n")); break; } while (*ps && *ps != ',') ps++; if (*ps == '\0') { dbg(("subsec = empty\n")); return; } *ps++ = '\0'; dbg(("subsec = |%s|\n", pd)); break; default: break; } pl++; } } } #define FP fprintf /*------------------------------*/ /* usage */ /*------------------------------*/ void usage (int excode) { char *ps; int i; #if 0 FP (stderr, "Usage: %s [-s sec[sub]] [-M dir | -m dir] [- [-ul]] [-k key] [-f file] [sec[sub]] name\n", myname); #endif FP (stderr, "\nUsage: %s [options] [sec[sub]] name\n", myname); FP (stderr, "Opts: -s sec[sub] section/subsect (e.g. 2g)\n"); FP (stderr, " -M dir specify search dir (for man tree)\n"); FP (stderr, " -m dir specify search dir (dir, no tree, eg man -m .)\n"); #ifdef HAS_CAT FP (stderr, " - use cat rather than more or less\n"); # ifdef HAS_UL FP (stderr, " - -ul use ul rather than cat\n"); # endif #endif #ifdef HAS_APROPOS FP (stderr, " -k key same as \"apropos keyword\"\n"); #endif #ifdef HAS_WHATIS FP (stderr, " -f file same as \"whatis file\"\n"); #endif FP (stderr, "Args: sec section, alternate for -s\n"); FP (stderr, " sub subsection, alternate for -s\n"); FP (stderr, " name desired entry (command, etc)\n"); FP (stderr, "Search order:\n"); if (envmansect_G) { for (ps = allsect; *ps; ps++) { switch (*ps) { case '0': FP (stderr, " %s0%s*.0", SUBDIRBASE, SLASH_STR); if (*subsec0) FP (stderr, "[%s]%s", subsec0, (strlen(subsec0) < 7) ? "\t " : " "); else FP (stderr, "\t\t "); FP (stderr, "general\n"); break; case '1': FP (stderr, " %s1%s*.1", SUBDIRBASE, SLASH_STR); if (*subsec1) FP (stderr, "[%s]%s", subsec1, (strlen(subsec1) < 7) ? "\t " : " "); else FP (stderr, "\t\t "); FP (stderr, "commands\n"); break; case '2': FP (stderr, " %s2%s*.2", SUBDIRBASE, SLASH_STR); if (*subsec2) FP (stderr, "[%s]%s", subsec2, (strlen(subsec2) < 7) ? "\t " : " "); else FP (stderr, "\t\t "); FP (stderr, "system calls\n"); break; case '3': FP (stderr, " %s3%s*.3", SUBDIRBASE, SLASH_STR); if (*subsec3) FP (stderr, "[%s]%s", subsec3, (strlen(subsec3) < 7) ? "\t " : " "); else FP (stderr, "\t\t "); FP (stderr, "library calls\n"); break; case '4': FP (stderr, " %s4%s*.4", SUBDIRBASE, SLASH_STR); if (*subsec4) FP (stderr, "[%s]%s", subsec4, (strlen(subsec4) < 7) ? "\t " : " "); else FP (stderr, "\t\t "); FP (stderr, "hardware\n"); break; case '5': FP (stderr, " %s5%s*.5", SUBDIRBASE, SLASH_STR); if (*subsec5) FP (stderr, "[%s]%s", subsec5, (strlen(subsec5) < 7) ? "\t " : " "); else FP (stderr, "\t\t "); FP (stderr, "special files\n"); break; case '6': FP (stderr, " %s6%s*.6", SUBDIRBASE, SLASH_STR); if (*subsec6) FP (stderr, "[%s]%s", subsec6, (strlen(subsec6) < 7) ? "\t " : " "); else FP (stderr, "\t\t "); FP (stderr, "games\n"); break; case '7': FP (stderr, " %s7%s*.7", SUBDIRBASE, SLASH_STR); if (*subsec7) FP (stderr, "[%s]%s", subsec7, (strlen(subsec7) < 7) ? "\t " : " "); else FP (stderr, "\t\t "); FP (stderr, "misc\n"); break; case '8': FP (stderr, " %s8%s*.8", SUBDIRBASE, SLASH_STR); if (*subsec8) FP (stderr, "[%s]%s", subsec8, (strlen(subsec8) < 7) ? "\t " : " "); else FP (stderr, "\t\t "); FP (stderr, "admin commands\n"); break; case '9': FP (stderr, " %s9%s*.9", SUBDIRBASE, SLASH_STR); if (*subsec9) FP (stderr, "[%s]%s", subsec9, (strlen(subsec9) < 7) ? "\t " : " "); else FP (stderr, "\t\t "); FP (stderr, "other\n"); break; } } } else { FP (stderr, " %s1%s*.1[tcgesla] cmds (util & text,com,graph,edit,shell,lang,archive)\n", SUBDIRBASE, SLASH_STR); FP (stderr, " %s0%s*.0 general\n", SUBDIRBASE, SLASH_STR); FP (stderr, " %s8%s*.8[s] admin (util & system)\n", SUBDIRBASE, SLASH_STR); FP (stderr, " %s2%s*.2[b] syslib (unix & bios)\n", SUBDIRBASE,SLASH_STR); FP (stderr, " %s3%s*.3[msvcxl] libs (C lib & math,stdio,sysV,compat,misc,local)\n", SUBDIRBASE, SLASH_STR); FP (stderr, " %s4%s*.4[dkvscm] h/w (gen & disk,keyboard,video,sound,chips,memory)\n", SUBDIRBASE, SLASH_STR); FP (stderr, " %s5%s*.5 special files\n", SUBDIRBASE,SLASH_STR); FP (stderr, " %s7%s*.7 misc\n", SUBDIRBASE, SLASH_STR); FP (stderr, " %s6%s*.6 games\n", SUBDIRBASE, SLASH_STR); } #ifdef LONG_SECT FP (stderr, "Other sections: "); for (i = 0; i < 10; i++) { if (longsect[i] == (char *) NULL) break; FP (stderr, "%s", longsect[i]); if (longsect[i+1]) FP (stderr, ","); } FP (stderr, "\n"); #else FP (stderr, "Other sections: local,new,old\n"); #endif FP (stderr, "Environment: MANPAGER,PAGER,MANPATH,MANSECT,BINDIR,TMPDIR\n"); exit (excode); } @EOF set `sum $sumopt man/man.man <<'@EOF' @.\" man v3.0.2 92/10/11 rosenkra @.TH MAN 1 @.SH NAME man \- read online documentation @.SH SYNOPSIS @.\" man [- [-ul]] [-s sect[subs]] [-M path] [-m path] [-e] [sect[subs]] name ... @.B man @.RB [ \- @.RB [ \-ul ]] @.RB [ \-s @.IR sect [ subs ]] @.RB [ \-M @.IR path ] @.RB [ \-m @.IR path ] @.RB [ \-e ] @.RI [ sect [ subs ]] @.IR name ... @.br @.\" man -f file @.B man @.B \-f @.IR file ... @.br @.\" man -k keyword... @.B man @.B \-k @.IR keyword ... @.SH DESCRIPTION The @.B man command finds and displays information in the online documentation set. When the standard output is a terminal, @.B man pipes its output through @.IR less (1) or the name of the command specified with the MANPAGER or PAGER environment variables. @.SH OPTIONS The following command line options are recognized: @.IP \fB\-\fR Pipes the output through @.IR cat (1) rather than @.IR less (1) or PAGER. @.IP "\fB\- \-ul\fR" Use @.IR ul (1) rather than @.IR cat (1). @.IP "\fB\-M\fR \fIpath\fR" Specifies a directory tree in which to search. By default, @.B man searches in c:\\usr\\man under MSDOS or on the Atari ST or /usr/man under Unix, or the directory specified by the MANPATH environment variable, the standard location for online documentation. The MANPATH variable should have a single path name at the present time (eventually, it will support a colon-separated list of locations). This option assumes @.I path is the root of a \*(lqnormal\*(rq directory structure. For compatibility with some Unix man systems, you can use @.B \-P as well as @.BR \-M . @.IP "\fB\-m\fR \fIpath\fR" Specifies a directory in which to search. This option does not use a directory tree. Files are searched only in the directory specified by @.IR path . This option is useful for debugging new manpages. For example, assuming you are working on a manpage named \*(lqmycmd.1\*(rq, you can do this: @.sp @.nf man -m . 1 mycmd @.fi @.IP \fB\-e\fR Find every manpage concerning the given @.I name regardless of section. It is expected that a \*(lqnormal\*(rq exit from the pager will result in an exit status of 0 (in which case the search is continued in other sections). An \*(lqabnormal\*(rq exit should result in a nonzero exit status and the search is then terminated. @.IP "\fB\-s\fR \fIsect\fR[\fIsubsect\fR]" Specifies a @.I section and @.I subsection similar to the 4.2 BSD UNIX Programmer's Manual (as explained below) in which to search. If no @.I section is specified, @.B man searches through all of the sections. Example: \*(lqman -s 3s fopen\*(rq. @.IP \fIsect\fR As an alternative to @.BR \-s , you can specify the section (and optional subsection) as the first argument. Example: \*(lqman 3s fopen\*(rq. @.IP \fIname\fR Searches for documentation files associated with the specified @.IR name . @.IP "\fB\-f\fR \fIname\fR" Displays a one line synopsis of each online documentation file whose names match the specified word (equivalent to the @.IR whatis (1) command). For example, \*(lqman -f chmod\*(rq will give entries for both @.IR chmod (1) and @.IR chmod (2). Note that @.B man invokes @.IR whatis (1) in this case, so it should be found in the path (see ENVIRONMENT). @.IP "\fB\-k\fR \fIkeyword\fR" Displays a one line synopsis of each online documentation file whose name or description contains the specified @.I keyword (equivalent to the @.IR apropos (1) command). Note that @.B man invokes @.IR apropos (1) in this case, so it should be found in the path (see ENVIRONMENT). @.SH ENVIRONMENT The following environment variables are recognized: @.IP MANSECT This can be used to alter the search order and to customize subsections. The default is equivalent to: @.sp @.nf setenv MANSECT 108234576,tcgesla,,s,mgbxl,msvcxgl,dkvscm,,, @.fi @.sp This means the major sections (man1, etc.) are searched in the order man1, man0, man8, etc. For each section, you can also provide a list of subsections which must correspond in the remaining list. In this case man1 subsections are t,c,g,e,s,l, and a; there are no subsections for man0; etc. The first entry (the section list) must consist of numbers from 0 to 9 @.IR only . Numbers can be skipped. @.sp The default search order is oriented toward users. To speed up the search, a casual programmer might perfer: @.sp @.nf 325481760,gsmcvxl,mgbxl,,dkvscm,s,tcgesla,,, @.fi @.sp while a Unix programmer might prefer: @.sp @.nf 235481760,mgbxl,csmxvlg,,dkvscm,s,tcgesla,,, @.fi @.IP MANPATH,MANDIR Location of main manual direcotry, where subdirectories are to be found. @.B Man uses (in order of priority) the path specified with @.BR \-M , the MANPATH specified, or the built-in default (c:\\usr\\man or /usr/man). @.IP MANPAGER Name of prefered pager. Use this pager if you have compressed manpages (see @.IR manpager (1)). @.B Man will use first MANPAGER, if found, then PAGER, if found. If neither are found, it uses c:\\usr\\bin\\less. @.IP PAGER Name of secondary pager to replace @.IR less (1). Use this if you do not have manpages generated with font changes (see @.IR nroff (1)). Either MANPAGER or PAGER should be defined. The search order is MANPAGER then PAGER. @.\" .IP BINDIR @.\" Alternate location to find all necessary executables. @.\" The default is c:\\bin. @.\" You need @.\" .BR less (1), @.\" .BR cat (1), @.\" and @.\" .BR ul (1) @.\" at a minimum. @.\" .IP TMPDIR @.\" Place to put temporary files, if necessary. @.\" Default is g:\\tmp. @.\" Make it a ramdisk partition, if you have one. @.\" So far this is not used. @.PP Note that BINDIR and TMPDIR are not currently used. @.SH "SECTION NAMES" By convention, the "sections" of the manual are (see @.IR whatisin (1) as well): @.sp @.nf Sect Section Name Description ---- ------------- -------------------------------------- 0 General overview of features and documentation 1 Commands user commands 2 System Calls low-level system library calls (C) 3 Library Calls standard user calls (C) 4 Special Files special system files and hardware 5 File formats things like arc(1) file formats 6 Games games manual 7 Miscellaneous miscellaneous information 8 Administration system administration commands @.fi @.sp In addition, this @.B man recognizes the following section names: @.sp @.nf local files specific to local system new files added since current software release old files from previous software release gnu GNU files (gcc typically) paper misc formal papers doc misc documentation @.fi @.PP The search order, if no section is specified, is: @.sp @.nf 108234576 @.fi @.PP In addition to sections, there are a number of subsections possible, though these files do not reside in a special directory. The subsection name is simply appended to the file name. Example: \*(lqfopen.3s\*(rq resides in $MANPATH\\man3, the section is \*(lq3\*(rq (libraries) and the subsection is \*(lqs\*(rq, stdio. Here is the subsection search order for subsections in each section (the square brackets mean a choice of each character contained in them, in that order): @.sp @.nf man1\\*.1[tcgesla] util & text,com,graphics,edit,shell,lang archival man0\\*.0 man8\\*.8[s] util & system man2\\*.2[mgbxl] system & mint,gemdos,bios,xbios,lineA man3\\*.3[msvcxgl] C lib & math,stdio,sysV,compat,extra gem(aes/vdi),local man4\\*.4[dkvscm] general & disk,keyboard,video,sound,chips memory man5\\*.5 man7\\*.7 man6\\*.6 @.fi @.SH NOTES To save disk space, you can "source" other files by including the @.BR nroff (1) directive \*(lq.so\*(rq in a file as the first line. In this case, the first line should start with .so followed by at least one space, then the file to use instead of the actual manpage. For example, the manpage for feof.3s (in $MANPATH\\man3) contains the single line: @.sp @.nf \&.so man3\\ferror.3s @.fi @.sp which will cause @.B man to display the contents of \*(lqferror.3s\*(rq instead. Note the relative path (relative to MANPATH, by default c:\\usr\\man). In this way, numerous manpages can refer to a single (larger) file. Do not compress files with source lines as @.B man only checks for this line if it finds a file which is not compressed. Note that you should only compress files for viewing with a pager that supports reading compressed files (e.g., @.BR manpager (1)) and must set the MANPAGER environment variable as well. @.PP You can also specify just a file name for sourcing (without relative path): @.sp @.nf \&.so ferror.3s @.fi @.sp and @.B man will use the relative path of the file containing this line. @.SH FILES @.nf c:\\usr\\man root of standard manual page directory tree c:\\usr\\man\\man*\\* manual entries c:\\usr\\man\\whatis table of contents and keyword database @.fi @.SH "SEE ALSO" apropos(1), cat(1), less(1), manpager(1), nroff(1), what(1), whatis(1), whatisin(1), whereis(1), man(7) @.SH AUTHOR Bill Rosenkranz @.br rosenkra AT convex DOT com @.SH VERSION man v3.0.2 92/10/11 rosenkra @EOF set `sum $sumopt